OSDN Git Service

Index: component/ChangeLog
authorbje <bje>
Fri, 15 Jun 2001 04:19:50 +0000 (04:19 +0000)
committerbje <bje>
Fri, 15 Jun 2001 04:19:50 +0000 (04:19 +0000)
2001-06-12  Ben Elliston  <bje@redhat.com>

* CATALOG: Add hw-cache-basic and friends.
* configure.in (make_subdirs): Add cache.
* configure: Regenerate.
* Makefile.in: Ditto.

Index: component/cache/ChangeLog
2001-06-15  Ben Elliston  <bje@redhat.com>

* cache.cxx: New file.
* cache.h: Likewise.
* cacheutil.cxx: Likewise.
* cacheutil.h: Likewise.
* log2.h: Likewise.
* hw-cache.txt: Likewise.

Index: component/testsuite/ChangeLog
2001-06-05  Ben Elliston  <bje@redhat.com>

* Makefile.am: New file.
* Makefile.in: Generate.

2001-06-15  Ben Elliston  <bje@redhat.com>

* sidcomp.cache/cache.exp: New test case.
* sidcomp.cache/cachedocs.exp: Ditto.
* sidcomp.cache/cachemonkey.exp: Ditto.
* sidcomp.cache/coherency.exp: Ditto.
* sidcomp.cache/fifo.exp: Ditto.
* sidcomp.cache/flush.exp: Ditto.
* sidcomp.cache/lock.exp: Ditto.
* sidcomp.cache/lru.exp: Ditto.
* sidcomp.cache/misaligned.exp: Ditto.
* sidcomp.cache/prefetch.exp: Ditto.
* sidcomp.cache/random.exp: Ditto.
* sidcomp.cache/types.exp: Ditto.
* sidcomp.cache/utils.exp: Ditto.
* sidcomp.cache/writealloc.exp: Ditto.
* sidcomp.cache/writethru.exp: Ditto.

30 files changed:
sid/component/CATALOG
sid/component/ChangeLog
sid/component/Makefile.in
sid/component/cache/ChangeLog [new file with mode: 0644]
sid/component/cache/Makefile.am [new file with mode: 0644]
sid/component/cache/Makefile.in [new file with mode: 0644]
sid/component/cache/cache.cxx [new file with mode: 0644]
sid/component/cache/cache.h [new file with mode: 0644]
sid/component/cache/cacheutil.cxx [new file with mode: 0644]
sid/component/cache/cacheutil.h [new file with mode: 0644]
sid/component/cache/hw-cache.txt [new file with mode: 0644]
sid/component/cache/log2.h [new file with mode: 0644]
sid/component/configure
sid/component/configure.in
sid/component/testsuite/ChangeLog
sid/component/testsuite/sidcomp.cache/cache.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/cachedocs.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/cachemonkey.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/coherency.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/fifo.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/flush.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/lock.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/lru.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/misaligned.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/prefetch.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/random.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/types.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/utils.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/writealloc.exp [new file with mode: 0644]
sid/component/testsuite/sidcomp.cache/writethru.exp [new file with mode: 0644]

index 336b321..41ac63d 100644 (file)
@@ -3,6 +3,7 @@ This is a current list of sid component shared libraries.
 DIRECTORY       DSO                     COMPONENT_LIBRARY                  MAINTAINERS
 
 audio           libaudio.la             audio_component_library            Red Hat
+cache          libcache.la             cache_component_library            Red Hat
 cfgroot         libconfig.la            config_component_library           Red Hat
 cgen-cpu        libcgencpu.la           cgen_component_library             Red Hat
 consoles        libconsoles.la          console_component_library          Red Hat
@@ -35,7 +36,9 @@ TYPE-NAME               DESCRIPTION
 bridge-tcl              TCL interpreter-based generic component shell
 bridge-tk               TCL/TK interpreter-based generic component shell
 bridge-blt              TCL/TK/BLT interpreter-based generic component shell
-hw-audio-sid            Fictional audio codec.
+hw-audio-sid            Fictional audio codec
+hw-cache-basic         Basic 16kb direct-mapped cache
+hw-cache-*             Other memory caches (ref. component docs)
 hw-cpu-arm7t            ARM7 / ARM7T CPU model
 hw-cpu-m32r/d           M32R/D CPU model
 hw-disk-ide             IDE hard drive model (controller + drives)
index a465ba3..01ec980 100644 (file)
@@ -1,3 +1,10 @@
+2001-06-12  Ben Elliston  <bje@redhat.com>
+
+       * CATALOG: Add hw-cache-basic and friends.
+       * configure.in (make_subdirs): Add cache.
+       * configure: Regenerate.
+       * Makefile.in: Ditto.
+
 2001-03-26  Frank Ch. Eigler  <fche@redhat.com>
 
        * CATALOG: Add hw-visual-probe-bus, hw-visual-probe-pin.
index 81c5cfa..4e5ffed 100644 (file)
@@ -116,9 +116,10 @@ Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status
          && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status
 
 $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in  \
-               ../config/am_rpm_init.m4 ../config/cgen-maint.m4 \
-               ../config/libstdc++.m4 ../config/libtool.m4 \
-               ../config/ltdl.m4 ../config/sidtargets.m4
+               ../config/am_rpm_init.m4 ../config/cgen-bfd-dis.m4 \
+               ../config/cgen-maint.m4 ../config/libstdc++.m4 \
+               ../config/libtool.m4 ../config/ltdl.m4 \
+               ../config/sidtargets.m4
        cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
 
 config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
diff --git a/sid/component/cache/ChangeLog b/sid/component/cache/ChangeLog
new file mode 100644 (file)
index 0000000..ee74387
--- /dev/null
@@ -0,0 +1,13 @@
+2001-06-15  Ben Elliston  <bje@redhat.com>
+
+       * cache.cxx: New file. 
+       * cache.h: Likewise.
+       * cacheutil.cxx: Likewise.
+       * cacheutil.h: Likewise.
+       * log2.h: Likewise.
+       * hw-cache.txt: Likewise.
+
+2001-06-05  Ben Elliston  <bje@redhat.com>
+
+       * Makefile.am: New file.
+       * Makefile.in: Generate.
diff --git a/sid/component/cache/Makefile.am b/sid/component/cache/Makefile.am
new file mode 100644 (file)
index 0000000..698876d
--- /dev/null
@@ -0,0 +1,18 @@
+## Process this with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+pkglib_LTLIBRARIES = libcache.la
+
+INCLUDES = -I. -I../../include -I$(srcdir)/../../include
+libcache_la_SOURCES = cache.cxx cache.h cacheutil.cxx cacheutil.h log2.h
+libcache_la_LDFLAGS = -module -no-undefined
+
+pkgdata_DATA = hw-cache.txt
+
+DEJAGNUTESTS=cache.exp cachemonkey.exp cachedocs.exp coherency.exp \
+       fifo.exp flush.exp lock.exp lru.exp misaligned.exp \
+       prefetch.exp random.exp writealloc.exp writethru.exp
+
+checkme: all
+       (cd ../testsuite ; $(MAKE) check RUNTESTFLAGS="$(RUNTESTFLAGS) $(DEJAGNUTESTS)")
diff --git a/sid/component/cache/Makefile.in b/sid/component/cache/Makefile.in
new file mode 100644 (file)
index 0000000..69d08ea
--- /dev/null
@@ -0,0 +1,416 @@
+# Makefile.in generated automatically by automake 1.4 from Makefile.am
+
+# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+
+DESTDIR =
+
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS)
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+transform = @program_transform_name@
+
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+host_alias = @host_alias@
+host_triplet = @host@
+AR = @AR@
+AS = @AS@
+CC = @CC@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CYGWIN = @CYGWIN@
+DLLTOOL = @DLLTOOL@
+EXEEXT = @EXEEXT@
+LD = @LD@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+NM = @NM@
+OBJDUMP = @OBJDUMP@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+VERSION = @VERSION@
+lcd_libs = @lcd_libs@
+make_subdirs = @make_subdirs@
+sidtarget_arm = @sidtarget_arm@
+sidtarget_m32r = @sidtarget_m32r@
+sidtarget_m68k = @sidtarget_m68k@
+sidtarget_mips = @sidtarget_mips@
+sidtarget_ppc = @sidtarget_ppc@
+socket_libs = @socket_libs@
+
+AUTOMAKE_OPTIONS = foreign
+
+pkglib_LTLIBRARIES = libcache.la
+
+INCLUDES = -I. -I../../include -I$(srcdir)/../../include
+libcache_la_SOURCES = cache.cxx cache.h cacheutil.cxx cacheutil.h log2.h
+libcache_la_LDFLAGS = -module -no-undefined
+
+pkgdata_DATA = hw-cache.txt
+
+DEJAGNUTESTS = cache.exp cachemonkey.exp cachedocs.exp coherency.exp \
+       fifo.exp flush.exp lock.exp lru.exp misaligned.exp \
+       prefetch.exp random.exp writealloc.exp writethru.exp
+
+mkinstalldirs = $(SHELL) $(top_srcdir)/../config/mkinstalldirs
+CONFIG_HEADER = ../config.h
+CONFIG_CLEAN_FILES = 
+LTLIBRARIES =  $(pkglib_LTLIBRARIES)
+
+
+DEFS = @DEFS@ -I. -I$(srcdir) -I..
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+libcache_la_LIBADD = 
+libcache_la_OBJECTS =  cache.lo cacheutil.lo
+CXXFLAGS = @CXXFLAGS@
+CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@
+DATA =  $(pkgdata_DATA)
+
+DIST_COMMON =  ChangeLog Makefile.am Makefile.in
+
+
+DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
+
+TAR = gtar
+GZIP_ENV = --best
+DEP_FILES =  .deps/cache.P .deps/cacheutil.P
+SOURCES = $(libcache_la_SOURCES)
+OBJECTS = $(libcache_la_OBJECTS)
+
+all: all-redirect
+.SUFFIXES:
+.SUFFIXES: .S .c .cxx .lo .o .s
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) 
+       cd $(top_srcdir) && $(AUTOMAKE) --foreign cache/Makefile
+
+Makefile: $(srcdir)/Makefile.in  $(top_builddir)/config.status $(BUILT_SOURCES)
+       cd $(top_builddir) \
+         && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status
+
+
+mostlyclean-pkglibLTLIBRARIES:
+
+clean-pkglibLTLIBRARIES:
+       -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+
+distclean-pkglibLTLIBRARIES:
+
+maintainer-clean-pkglibLTLIBRARIES:
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(pkglibdir)
+       @list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+         if test -f $$p; then \
+           echo "$(LIBTOOL)  --mode=install $(INSTALL) $$p $(DESTDIR)$(pkglibdir)/$$p"; \
+           $(LIBTOOL)  --mode=install $(INSTALL) $$p $(DESTDIR)$(pkglibdir)/$$p; \
+         else :; fi; \
+       done
+
+uninstall-pkglibLTLIBRARIES:
+       @$(NORMAL_UNINSTALL)
+       list='$(pkglib_LTLIBRARIES)'; for p in $$list; do \
+         $(LIBTOOL)  --mode=uninstall rm -f $(DESTDIR)$(pkglibdir)/$$p; \
+       done
+
+.s.o:
+       $(COMPILE) -c $<
+
+.S.o:
+       $(COMPILE) -c $<
+
+mostlyclean-compile:
+       -rm -f *.o core *.core
+
+clean-compile:
+
+distclean-compile:
+       -rm -f *.tab.c
+
+maintainer-clean-compile:
+
+.s.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+.S.lo:
+       $(LIBTOOL) --mode=compile $(COMPILE) -c $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+
+maintainer-clean-libtool:
+
+libcache.la: $(libcache_la_OBJECTS) $(libcache_la_DEPENDENCIES)
+       $(CXXLINK) -rpath $(pkglibdir) $(libcache_la_LDFLAGS) $(libcache_la_OBJECTS) $(libcache_la_LIBADD) $(LIBS)
+.cxx.o:
+       $(CXXCOMPILE) -c $<
+.cxx.lo:
+       $(LTCXXCOMPILE) -c $<
+
+install-pkgdataDATA: $(pkgdata_DATA)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+       @list='$(pkgdata_DATA)'; for p in $$list; do \
+         if test -f $(srcdir)/$$p; then \
+           echo " $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkgdatadir)/$$p"; \
+           $(INSTALL_DATA) $(srcdir)/$$p $(DESTDIR)$(pkgdatadir)/$$p; \
+         else if test -f $$p; then \
+           echo " $(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p"; \
+           $(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
+         fi; fi; \
+       done
+
+uninstall-pkgdataDATA:
+       @$(NORMAL_UNINSTALL)
+       list='$(pkgdata_DATA)'; for p in $$list; do \
+         rm -f $(DESTDIR)$(pkgdatadir)/$$p; \
+       done
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP)
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       here=`pwd` && cd $(srcdir) \
+         && mkid -f$$here/ID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS)'; \
+       unique=`for i in $$list; do echo $$i; done | \
+         awk '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags  $$unique $(LISP) -o $$here/TAGS)
+
+mostlyclean-tags:
+
+clean-tags:
+
+distclean-tags:
+       -rm -f TAGS ID
+
+maintainer-clean-tags:
+
+distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir)
+
+subdir = cache
+
+distdir: $(DISTFILES)
+       here=`cd $(top_builddir) && pwd`; \
+       top_distdir=`cd $(top_distdir) && pwd`; \
+       distdir=`cd $(distdir) && pwd`; \
+       cd $(top_srcdir) \
+         && $(AUTOMAKE) --include-deps --build-dir=$$here --srcdir-name=$(top_srcdir) --output-dir=$$top_distdir --foreign cache/Makefile
+       @for file in $(DISTFILES); do \
+         d=$(srcdir); \
+         if test -d $$d/$$file; then \
+           cp -pr $$d/$$file $(distdir)/$$file; \
+         else \
+           test -f $(distdir)/$$file \
+           || ln $$d/$$file $(distdir)/$$file 2> /dev/null \
+           || cp -p $$d/$$file $(distdir)/$$file || :; \
+         fi; \
+       done
+
+DEPS_MAGIC := $(shell mkdir .deps > /dev/null 2>&1 || :)
+
+-include $(DEP_FILES)
+
+mostlyclean-depend:
+
+clean-depend:
+
+distclean-depend:
+       -rm -rf .deps
+
+maintainer-clean-depend:
+
+%.o: %.c
+       @echo '$(COMPILE) -c $<'; \
+       $(COMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-cp .deps/$(*F).pp .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm .deps/$(*F).pp
+
+%.lo: %.c
+       @echo '$(LTCOMPILE) -c $<'; \
+       $(LTCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-sed -e 's/^\([^:]*\)\.o[      ]*:/\1.lo \1.o :/' \
+         < .deps/$(*F).pp > .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm -f .deps/$(*F).pp
+
+%.o: %.cxx
+       @echo '$(CXXCOMPILE) -c $<'; \
+       $(CXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-cp .deps/$(*F).pp .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm .deps/$(*F).pp
+
+%.lo: %.cxx
+       @echo '$(LTCXXCOMPILE) -c $<'; \
+       $(LTCXXCOMPILE) -Wp,-MD,.deps/$(*F).pp -c $<
+       @-sed -e 's/^\([^:]*\)\.o[      ]*:/\1.lo \1.o :/' \
+         < .deps/$(*F).pp > .deps/$(*F).P; \
+       tr ' ' '\012' < .deps/$(*F).pp \
+         | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \
+           >> .deps/$(*F).P; \
+       rm -f .deps/$(*F).pp
+info-am:
+info: info-am
+dvi-am:
+dvi: dvi-am
+check-am: all-am
+check: check-am
+installcheck-am:
+installcheck: installcheck-am
+install-exec-am: install-pkglibLTLIBRARIES
+install-exec: install-exec-am
+
+install-data-am: install-pkgdataDATA
+install-data: install-data-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+install: install-am
+uninstall-am: uninstall-pkglibLTLIBRARIES uninstall-pkgdataDATA
+uninstall: uninstall-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+all-redirect: all-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install
+installdirs:
+       $(mkinstalldirs)  $(DESTDIR)$(pkglibdir) $(DESTDIR)$(pkgdatadir)
+
+
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES)
+       -rm -f config.cache config.log stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+mostlyclean-am:  mostlyclean-pkglibLTLIBRARIES mostlyclean-compile \
+               mostlyclean-libtool mostlyclean-tags mostlyclean-depend \
+               mostlyclean-generic
+
+mostlyclean: mostlyclean-am
+
+clean-am:  clean-pkglibLTLIBRARIES clean-compile clean-libtool \
+               clean-tags clean-depend clean-generic mostlyclean-am
+
+clean: clean-am
+
+distclean-am:  distclean-pkglibLTLIBRARIES distclean-compile \
+               distclean-libtool distclean-tags distclean-depend \
+               distclean-generic clean-am
+       -rm -f libtool
+
+distclean: distclean-am
+
+maintainer-clean-am:  maintainer-clean-pkglibLTLIBRARIES \
+               maintainer-clean-compile maintainer-clean-libtool \
+               maintainer-clean-tags maintainer-clean-depend \
+               maintainer-clean-generic distclean-am
+       @echo "This command is intended for maintainers to use;"
+       @echo "it deletes files that may require special tools to rebuild."
+
+maintainer-clean: maintainer-clean-am
+
+.PHONY: mostlyclean-pkglibLTLIBRARIES distclean-pkglibLTLIBRARIES \
+clean-pkglibLTLIBRARIES maintainer-clean-pkglibLTLIBRARIES \
+uninstall-pkglibLTLIBRARIES install-pkglibLTLIBRARIES \
+mostlyclean-compile distclean-compile clean-compile \
+maintainer-clean-compile mostlyclean-libtool distclean-libtool \
+clean-libtool maintainer-clean-libtool uninstall-pkgdataDATA \
+install-pkgdataDATA tags mostlyclean-tags distclean-tags clean-tags \
+maintainer-clean-tags distdir mostlyclean-depend distclean-depend \
+clean-depend maintainer-clean-depend info-am info dvi-am dvi check \
+check-am installcheck-am installcheck install-exec-am install-exec \
+install-data-am install-data install-am install uninstall-am uninstall \
+all-redirect all-am all installdirs mostlyclean-generic \
+distclean-generic clean-generic maintainer-clean-generic clean \
+mostlyclean distclean maintainer-clean
+
+
+checkme: all
+       (cd ../testsuite ; $(MAKE) check RUNTESTFLAGS="$(RUNTESTFLAGS) $(DEJAGNUTESTS)")
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/sid/component/cache/cache.cxx b/sid/component/cache/cache.cxx
new file mode 100644 (file)
index 0000000..ffb95be
--- /dev/null
@@ -0,0 +1,748 @@
+// cache.cxx -- A universal memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "config.h"
+
+#include <sidcomp.h>
+#include <sidso.h>
+#include <sidcomputil.h>
+#include <sidattrutil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidtypes.h>
+
+#include <algorithm>
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include "cache.h"
+
+string line_sizes[] =
+  { "16", "32", "64", "128" };
+
+string cache_sizes[] =
+  { "8", "16", "32", "64", "128", "256", "512" };
+
+string assocs[] =
+  { "direct", "full", "2way", "4way" };
+
+string replacement_algorithms[] =
+  { "lru", "fifo", "random" }; 
+
+// One per replacement policy
+static cache_replacement_null null_replacement;
+static cache_replacement_lru lru_replacement;
+static cache_replacement_fifo fifo_replacement;
+static cache_replacement_random random_replacement;
+
+cache_component::cache_component (unsigned assocy,
+                                 unsigned cache_sz, 
+                                 unsigned line_sz,
+                                 cache_replacement_algorithm& replacer)
+  :report_pin (this, &cache_component::emit_report),
+   flush_pin (this, &cache_component::flush_line),
+   invalidate_all_pin (this, &cache_component::invalidate_all_lines),
+   invalidate_pin (this, &cache_component::invalidate_line),
+   prefetch_pin (this, &cache_component::prefetch_line),
+   lock_pin (this, &cache_component::lock_line),
+   unlock_pin (this, &cache_component::unlock_line),
+   write_allocate_p (false),
+   write_through_p (false),
+   downstream (0),
+   upstream (*this),
+   collect_p (true),
+   line_size (line_sz),
+   cache_size (cache_sz),
+   assoc (assocy),
+   report_heading ("cache profile report"),
+   acache (cache_sz, line_sz, assocy, replacer)
+{
+  memset (&stats, 0, sizeof (stats));
+
+  add_bus ("upstream", &upstream);
+  add_accessor ("downstream", &downstream);
+  
+  add_pin ("report!", &report_pin);
+  add_pin ("flush", &flush_pin);
+  add_pin ("invalidate-all", &invalidate_all_pin);
+  add_pin ("invalidate", &invalidate_pin);
+  add_pin ("prefetch", &prefetch_pin);
+  add_pin ("lock", &lock_pin);  
+  add_pin ("unlock", &unlock_pin);
+  
+  add_attribute_ro ("cache-size", &cache_size, "setting");
+  add_attribute_ro ("line-size", &line_size, "setting");
+  add_attribute_virtual ("associativity", this,
+                        &cache_component::associativity,
+                        &cache_component::set_nothing,
+                        "setting");
+
+  add_attribute ("write-through?", &write_through_p, "setting");
+  add_attribute ("write-allocate?", &write_allocate_p, "setting");
+
+  add_attribute_virtual ("hash-bit-mask", this,
+                        &cache_component::get_hash_mask,
+                        &cache_component::set_hash_mask,
+                        "setting");
+
+  add_attribute_virtual ("hash-shift-amount", this,
+                        &cache_component::get_hash_shift,
+                        &cache_component::set_hash_shift,
+                        "setting");
+
+  add_attribute ("collect-statistics?", &collect_p, "setting");
+  add_attribute ("report-heading", &report_heading, "setting");
+  
+  add_attribute_virtual ("dump!", this,
+                        &cache_component::get_nothing,
+                        &cache_component::dump,
+                        "setting");
+
+  add_attribute_ro ("read-accesses", &stats.reads, "register");
+  add_attribute_ro ("write-accesses", &stats.writes, "register");
+  add_attribute_ro ("misaligned-reads", &stats.misaligned_reads, "register");
+  add_attribute_ro ("misaligned-writes", &stats.misaligned_writes, "register");
+  add_attribute_ro ("flushes", &stats.flushes, "register");
+  add_attribute_ro ("replacements", &stats.replacements, "register");
+
+  add_attribute_virtual ("read-hit-rate", this,
+                        &cache_component::read_hit_rate,
+                        &cache_component::set_nothing,
+                        "register");
+  
+  add_attribute_virtual ("write-hit-rate", this,
+                        &cache_component::write_hit_rate,
+                        &cache_component::set_nothing,
+                        "register");
+
+  // FIXME: state save/restore
+}
+
+unsigned
+cache_component::line_offset (const cache_line& line, const host_int_4& addr)
+{
+  return addr - acache.tag_to_addr (line.tag ());
+}
+
+template <typename DataType>
+bus::status
+cache_component::write_any (host_int_4 addr, DataType data)
+{
+  bool hit;
+  bus::status st;
+
+  if (UNLIKELY (downstream == 0))
+    return bus::unmapped;
+
+  if (LIKELY (collect_p))
+    stats.writes++;
+
+  if (UNLIKELY (addr % sizeof (data) != 0))
+    {
+      // Punt on misaligned accesses
+      if (LIKELY (collect_p))
+       stats.misaligned_writes++;
+
+      cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+      if (hit)
+      {
+       if (line.dirty_p ())
+        {      
+         // flush a dirty line being replaced
+         if ((st = write_line (line)) != bus::ok)
+           return st;
+       }
+       acache.expunge (line);
+      }
+      return downstream->read (addr, data);
+    }
+
+  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+  if (LIKELY (hit))
+    {
+      if (LIKELY (collect_p))
+       stats.write_hits++;
+      line.insert (line_offset (line, addr), data);
+      if (write_through_p)
+       {
+         if ((st = downstream->write (addr, data)) != bus::ok)
+           return st;
+       }
+    }
+  else
+    {
+      if (write_allocate_p)
+       {
+         if (acache.vacancy_p (addr))
+           {
+             cache_line expelled_line (line_size);
+             cache_line new_line (line_size, acache.addr_to_tag (addr));
+             if ((st = read_line (new_line)) != bus::ok)
+               return st;
+             
+             new_line.insert (line_offset (new_line, addr), data);
+             acache.replace (expelled_line, new_line);
+             
+             if (collect_p)
+               stats.replacements++;
+             
+             if (expelled_line.dirty_p () && !write_through_p)
+               {
+                 // flush a dirty line being replaced
+                 if ((st = write_line (expelled_line)) != bus::ok)
+                   return st;
+               }
+             
+             if (write_through_p)
+               {
+                 if ((st = downstream->write (addr, data)) != bus::ok)
+                   return st;
+               }
+           }
+       }
+      else
+       {
+         // write through to memory to preserve the write
+         if ((st = downstream->write (addr, data)) != bus::ok)
+           return st;
+       }
+    }
+  return bus::ok;
+}
+
+template <typename DataType>
+bus::status
+cache_component::read_any (host_int_4 addr, DataType& data)
+{
+  if (UNLIKELY (downstream == 0))
+    return bus::unmapped;
+
+  if (LIKELY (collect_p))
+    stats.reads++;
+
+  // Punt on misaligned accesses
+  if (UNLIKELY (addr % sizeof (data) != 0))
+    {
+      if (LIKELY (collect_p))
+       stats.misaligned_reads++;
+      return downstream->read (addr, data);
+    }
+
+  bool hit;
+  bus::status st;
+
+  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+  if (LIKELY (hit))
+    {
+      if (LIKELY (collect_p))
+       stats.read_hits++;
+      line.extract (line_offset (line, addr), data);
+    }
+  else
+    {
+      // miss!
+      if (acache.vacancy_p (addr))
+       {
+         cache_line expelled_line (line_size);
+         cache_line new_line (line_size, acache.addr_to_tag (addr));
+         
+         if ((st = read_line (new_line)) != bus::ok)
+           return st;
+         new_line.extract (line_offset (new_line, addr), data);
+
+         acache.replace (expelled_line, new_line);
+
+         if (collect_p)
+           stats.replacements++;
+         
+         if (expelled_line.dirty_p ())
+           {
+             // flush a dirty line being replaced
+             if ((st = write_line (expelled_line)) != bus::ok)
+               return st;
+           }
+       }
+      else
+       return downstream->read (addr, data);
+    }
+  return bus::ok;
+}
+
+bus::status
+cache_component::read_line (cache_line& line)
+{
+  host_int_4 base = acache.tag_to_addr (line.tag ());
+  for (host_int_4 offset = 0; offset < line_size; offset += 4)
+    {
+      sid::big_int_4 data;
+      bus::status st = downstream->read (base + offset, data);
+      if (st != bus::ok)
+       return st;
+      line.insert (offset, data);
+    }
+  line.unlock ();
+  line.clean ();
+  line.validate ();
+  return bus::ok;
+}
+
+bus::status
+cache_component::write_line (cache_line& line)
+{
+  host_int_4 base = acache.tag_to_addr (line.tag ());
+  for (host_int_4 offset = 0; offset < line_size; offset += 4)
+    {
+      sid::big_int_4 data;
+      line.extract (offset, data);
+      bus::status st = downstream->write (base + offset, data);
+      if (st != bus::ok)
+       return st;
+    }
+  line.clean ();
+  if (LIKELY (collect_p))
+    stats.flushes++;
+  return bus::ok;
+}
+
+void
+cache_component::flush_line (host_int_4 addr)
+{
+  bool hit;
+  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+  if (hit && line.dirty_p ())
+    bus::status st = write_line (line);
+}
+
+void
+cache_component::invalidate_all_lines (host_int_4 ignore)
+{
+  acache.invalidate ();
+}
+
+void
+cache_component::invalidate_line (host_int_4 addr)
+{
+  bool hit;
+  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+  if (hit)
+    line.invalidate ();
+}
+
+void
+cache_component::prefetch_line (host_int_4 addr)
+{
+  sid::big_int_1 dummy;
+  bus::status st = read_any (addr, dummy);
+}
+
+void
+cache_component::lock_line (host_int_4 addr)
+{
+  bool hit;
+  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+  if (hit)
+    line.lock ();
+}
+
+void
+cache_component::unlock_line (host_int_4 addr)
+{
+  bool hit;
+  cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+  if (hit)
+    line.unlock ();
+}
+
+void
+cache_component::emit_report (host_int_4 ignore)
+{
+  cout << report_heading << endl << endl
+       << "reads:        " << make_attribute (stats.reads) << endl
+       << "read hits:    " << read_hit_rate () << endl
+       << "writes:       " << make_attribute (stats.writes) << endl
+       << "write hits:   " << write_hit_rate () << endl
+       << "replacements: " << make_attribute (stats.replacements) << endl
+       << "flushes:      " << make_attribute (stats.flushes) << endl;
+}
+
+string
+cache_component::get_hash_mask ()
+{
+  return make_attribute (acache.hash_params.mask);
+}
+
+string
+cache_component::get_hash_shift ()
+{
+  return make_attribute (acache.hash_params.shift);
+}
+
+sid::component::status
+cache_component::set_hash_mask (const string& value)
+{
+  unsigned shift;
+  parse_attribute (value, shift);
+
+  if ((acache.hash_params.mask >> shift) >= acache.num_sets ())
+    return sid::component::bad_value;
+
+  acache.hash_params.shift = shift;
+  return sid::component::ok;
+}
+
+sid::component::status
+cache_component::set_hash_shift (const string& value)
+{
+  sid::host_int_4 mask;
+  parse_attribute (value, mask);
+
+  if ((mask >> acache.hash_params.shift) >= acache.num_sets ())
+    return sid::component::bad_value;
+
+  acache.hash_params.mask = mask;
+  return sid::component::ok;
+}
+
+sid::component::status
+cache_component::dump (const string& ignore)
+{
+  acache.dump ();
+  return sid::component::ok;
+}
+
+string
+cache_component::associativity ()
+{
+  switch (assoc)
+    {
+    case 0:
+      return "fully-associative";
+    case 1:
+      return "direct-mapped";
+    default:
+      return make_attribute (assoc) + "-way";
+    }
+}
+
+string
+cache_component::read_hit_rate ()
+{
+  if (stats.reads == 0)
+    return "0%";
+  else
+    {
+      float rate = (static_cast<float> (stats.read_hits) / stats.reads) * 100;
+      return make_attribute (static_cast<int> (rate)) + "%";
+    }
+}
+
+string
+cache_component::write_hit_rate ()
+{
+  if (stats.writes == 0)
+    return "0%";
+  else
+    {
+      float rate = (static_cast<float> (stats.write_hits) / stats.writes) * 100;
+      return make_attribute (static_cast<int> (rate)) + "%";
+    }
+}
+\f
+void
+cache_replacement_fifo::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+  // If this is the first time through, expand fifo accordingly.
+  if (fifo.size () != cset.num_lines ())
+    fifo.resize (cset.num_lines ());
+
+  for (unsigned i = 0; i < fifo.size (); i++)
+    fifo[i]++;
+
+  unsigned i;
+  vector<int> candidates(fifo);
+
+  int n = fifo.size ();
+  while (n > 0)
+    {
+      vector<int>::iterator it;
+      it = max_element (candidates.begin (), candidates.end ());
+      i = distance (candidates.begin (), it);
+      cache_line& line = cset.get_line (i);
+      if (line.locked_p ())
+       {
+         *it = -1;
+       }
+      else 
+       {
+         old_line = line;
+         old_line.invalidate ();
+         cset.set_line (i, new_line);
+
+         // update state
+         fifo[i] = 0;
+         return;
+       }
+      n--;
+    }
+}
+
+void
+cache_replacement_lru::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+  int oldest;
+  int index = -1;
+  lru.resize (cset.num_lines ());
+
+  for (unsigned i = 0, oldest = 0; i < cset.num_lines (); i++)
+    {
+      cache_line& line = cset.get_line (i);
+      if (!line.valid_p ())
+       {
+         index = i;
+         break;
+       }
+      else if (!line.locked_p () && lru[i] > oldest)
+       {
+         index = i;
+         oldest = lru[i];
+       }
+    }
+
+  if (index < 0)
+    return;
+  
+  old_line = cset.get_line (index);
+  old_line.invalidate ();
+  cset.set_line (index, new_line);
+  lru[index] = 0;
+}
+
+void
+cache_replacement_lru::update (cache_set& cset, cache_line& selected_line)
+{
+  cache_tag t = selected_line.tag ();
+  for (unsigned i = 0; i < lru.size (); i++)
+    {
+      if (cset.get_line (i) == t)
+       lru[i] = 0;
+      else
+       lru[i]++;
+    }
+}
+
+void
+cache_replacement_null::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+  cache_line& line = cset.get_line (0);
+  if (!line.locked_p ())
+    {
+      old_line = line;
+      old_line.invalidate ();
+      cset.set_line (0, new_line);
+    }
+}
+
+void
+cache_replacement_random::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+  for (unsigned i = 0; i < cset.num_lines (); i++)
+    {
+      cache_line& line = cset.get_line (i);
+      if (!line.valid_p ())
+       {
+         old_line = line;
+         old_line.invalidate ();
+         cset.set_line (i, new_line);
+         return;
+       }
+    }
+
+  unsigned n = cset.num_lines ();
+  vector<bool> candidates(n, true);
+
+  while (n > 0)
+    {
+      unsigned i = rand () % cset.num_lines ();
+      
+      // Try, try again.
+      if (!candidates[i]) continue;
+
+      cache_line& line = cset.get_line (i);
+      if (!line.locked_p ())
+       {
+         old_line = line;
+         old_line.invalidate ();
+         cset.set_line (i, new_line);
+         return;
+       }
+      else
+       {
+         candidates[i] = false;
+         n--;
+       }
+    }
+}
+
+\f
+extern const sid::component_library cache_component_library;
+
+static vector<string>
+CacheListTypes ()
+{
+  string type;
+  vector<string> types;
+
+  types.push_back ("hw-cache-basic");
+
+  for (int i = 0; i < (sizeof (assocs) / sizeof (string)); i++)
+    for (int j = 0; j < (sizeof (cache_sizes) / sizeof (string)); j++)
+      for (int k = 0; k < (sizeof (line_sizes) / sizeof (string)); k++)
+       {
+         if (assocs[i] == "direct")
+           {
+             type = string ("hw-cache-direct/");
+             type += cache_sizes[j] + "kb/";
+             type += line_sizes[k];
+             types.push_back (type);
+           }
+         else
+           for (int m = 0;
+                m < (sizeof (replacement_algorithms) / sizeof (string)); m++)
+             {
+               type = string ("hw-cache-");
+               type += assocs[i] + "/";
+               type += cache_sizes[j] + "kb/";
+               type += line_sizes[k] + "/";
+               type += replacement_algorithms[m];
+               types.push_back (type);
+             }
+       }
+  return types;
+}
+
+static component*
+CacheCreate (const string& typeName)
+{
+  bool match;
+  int i, index = 0, pos;
+  int assoc, linesz, cachesz;
+
+  if (typeName == "hw-cache-basic")
+    return new cache_component (1, 16384, 32, null_replacement);
+
+  if (typeName.find ("hw-cache-", index) != 0)
+    return 0;
+  index += strlen ("hw-cache-");
+  
+  // parse assoc + "/"
+  if ((pos = typeName.find_first_of ("/", index)) == string::npos)
+    return 0;
+  string assoc_string = typeName.substr (index, (pos - index));
+  index = pos + 1;
+
+  string cache_size_string;
+
+  // Parse "<x>kb", where <x> is a positive integer. 
+  if ((pos = typeName.find_first_of ("/", index)) == string::npos)
+    return 0;
+  cache_size_string = typeName.substr (index, (pos - index));
+  index = pos + 1;
+
+  if ((pos = cache_size_string.find ("kb", 0)) == string::npos)
+    return 0;
+  cache_size_string.erase (pos, cache_size_string.length () - pos);
+
+  string line_size_string;
+  string replace_alg_string;
+
+  if (assoc_string == "direct")
+    line_size_string = typeName.substr (index, (typeName.length () - index));
+  else
+    {
+      if ((pos = typeName.find_first_of ("/", index)) == string::npos)
+       return 0;
+      line_size_string = typeName.substr (index, (pos - index));
+      index = pos + 1;
+      replace_alg_string = typeName.substr (index, (typeName.length () - index));
+    }
+
+  for (match = false, i = 0; i < sizeof (assocs) / sizeof (string); i++)
+    if (assoc_string == assocs[i]) 
+      match = true;
+  if (!match)
+    return 0;
+
+  for (match = false, i = 0; i < sizeof (cache_sizes) / sizeof (string); i++)
+    if (cache_size_string == cache_sizes[i])
+      {
+       cachesz = atoi (cache_size_string.c_str ()) * 1024;
+       match = true;
+      }
+  if (!match)
+    return 0;
+  
+  for (match = false, i = 0; i < sizeof (line_sizes) / sizeof (string); i++)
+    if (line_size_string == line_sizes[i])
+      {
+       linesz = atoi (line_size_string.c_str ());
+       match = true;
+      }
+  if (!match)
+    return 0;
+  
+  if (assoc_string != "direct")
+    {
+      for (match = false, i = 0;
+          i < sizeof (replacement_algorithms) / sizeof (string); i++)
+       {
+         if (replace_alg_string == replacement_algorithms[i])
+           match = true;
+       }
+      if (!match)
+       return 0;
+    }
+
+  if (assoc_string == "full")
+    assoc = 0;
+  else if (assoc_string == "direct")
+    assoc = 1;
+  else
+    {
+      if ((pos = assoc_string.find ("way", 0)) == string::npos)
+        return 0;
+      assoc_string.erase (pos, assoc_string.length () - pos);
+      if ((assoc = atoi (assoc_string.c_str ())) == 0)
+        return 0;
+    }
+
+  if (assoc == 1)
+    return new cache_component (assoc, cachesz, linesz, null_replacement);
+
+  if (replace_alg_string == "lru")
+    return new cache_component (assoc, cachesz, linesz, lru_replacement);
+  else if (replace_alg_string == "fifo")
+    return new cache_component (assoc, cachesz, linesz, fifo_replacement);
+  else if (replace_alg_string == "random")
+    return new cache_component (assoc, cachesz, linesz, random_replacement);
+
+  return 0;
+}
+
+static void
+CacheDelete (component* c)
+{
+  delete dynamic_cast<cache_component*>(c);
+}
+
+const sid::component_library cache_component_library DLLEXPORT =
+{
+  sid::COMPONENT_LIBRARY_MAGIC,
+  &CacheListTypes,
+  &CacheCreate,
+  &CacheDelete
+};
diff --git a/sid/component/cache/cache.h b/sid/component/cache/cache.h
new file mode 100644 (file)
index 0000000..525306e
--- /dev/null
@@ -0,0 +1,186 @@
+// cache.h -- A universal memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef CACHE_H
+#define CACHE_H
+
+#include "cacheutil.h"
+
+using std::string;
+using std::vector;
+
+using sid::bus;
+using sid::component;
+using sid::host_int_4;
+
+using sidutil::fixed_attribute_map_component;
+using sidutil::fixed_bus_map_component;
+using sidutil::fixed_pin_map_component;
+using sidutil::fixed_accessor_map_component;
+using sidutil::no_relation_component;
+using sidutil::callback_pin;
+using sidutil::make_attribute;
+using sidutil::parse_attribute;
+
+class cache_component;
+class cache_bus: public bus
+{
+public:
+  cache_bus (cache_component& c)
+    :cache(c) {}
+
+private:
+  cache_component& cache;
+
+  template <typename DataType>
+  bus::status write_any (host_int_4 addr, DataType data)
+  {
+    return cache.write_any (addr, data);
+  }
+  
+  template <typename DataType>
+  bus::status read_any (host_int_4 addr, DataType& data)
+  {
+    return cache.read_any (addr, data);
+  }
+
+#define DEFN_METHOD(DataType) \
+  bus::status write(host_int_4 addr, DataType data) throw () { return this->write_any(addr, data); } \
+  bus::status read(host_int_4 addr, DataType& data) throw () { return this->read_any(addr, data); }
+  
+  DEFN_METHOD (sid::big_int_1)
+  DEFN_METHOD (sid::big_int_2)
+  DEFN_METHOD (sid::big_int_4)
+  DEFN_METHOD (sid::big_int_8)
+  DEFN_METHOD (sid::little_int_1)
+  DEFN_METHOD (sid::little_int_2)
+  DEFN_METHOD (sid::little_int_4)
+  DEFN_METHOD (sid::little_int_8)
+};
+
+// FIFO cache replacement algorithm
+
+class cache_replacement_fifo: public cache_replacement_algorithm
+{
+public:
+  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+
+private:
+  vector <int> fifo;
+};
+
+// Least recently used (LRU) replacement algorithm
+
+class cache_replacement_lru: public cache_replacement_algorithm
+{
+public:
+  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+  void update (cache_set& cset, cache_line& selected);
+
+private:
+  vector <int> lru;
+};
+
+// Random replacement algorithm
+
+class cache_replacement_random: public cache_replacement_algorithm
+{
+public:
+  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+};
+
+// Null replacement algorithm; used by direct mapped caches
+
+class cache_replacement_null: public cache_replacement_algorithm
+{
+public:
+  void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+};
+
+\f
+class cache_component: public virtual component,
+                      protected fixed_attribute_map_component,
+                      protected fixed_bus_map_component,
+                      protected fixed_pin_map_component,
+                      protected fixed_accessor_map_component,
+                      protected no_relation_component
+{
+public:
+  cache_component (unsigned asoctvty, unsigned cache_sz,
+                  unsigned line_sz, cache_replacement_algorithm& replacer);
+
+  template <typename DataType> bus::status 
+  write_any (host_int_4 addr, DataType data);
+  
+  template <typename DataType> bus::status
+  read_any (host_int_4 addr, DataType& data);
+
+private:
+  cache acache;
+
+  cache_bus upstream;
+  bus* downstream;
+
+  callback_pin<cache_component> report_pin;
+  void emit_report (host_int_4 ignore);
+
+  callback_pin<cache_component> flush_pin;
+  void flush_line (host_int_4 addr);
+
+  callback_pin<cache_component> invalidate_all_pin;
+  void invalidate_all_lines (host_int_4 ignore);
+
+  callback_pin<cache_component> invalidate_pin;
+  void invalidate_line (host_int_4 addr);
+
+  callback_pin<cache_component> prefetch_pin;
+  void prefetch_line (host_int_4 addr);
+
+  callback_pin<cache_component> lock_pin;
+  void lock_line (host_int_4 addr);
+
+  callback_pin<cache_component> unlock_pin;
+  void unlock_line (host_int_4 addr);
+
+  string read_hit_rate ();
+  string write_hit_rate ();
+  string get_nothing () { return ""; }
+  status set_nothing (const string& ignore) { return sid::component::ok; }
+  string associativity ();
+  status dump (const string& ignore);
+  string get_hash_mask ();
+  status set_hash_mask (const string& ignore);
+  string get_hash_shift ();
+  status set_hash_shift (const string& ignore);
+
+  unsigned line_offset (const cache_line& line, const host_int_4& addr); 
+
+  bus::status read_line (cache_line& line);
+  bus::status write_line (cache_line& line);
+
+  bool write_allocate_p;
+  bool write_through_p;
+  bool collect_p;
+  string report_heading;
+
+  struct
+  {
+    unsigned long reads;
+    unsigned long writes;
+    unsigned long read_hits;
+    unsigned long write_hits;
+    unsigned long misaligned_reads;
+    unsigned long misaligned_writes;
+    unsigned long flushes;
+    unsigned long replacements;
+  } stats;
+
+  unsigned line_size;
+  unsigned cache_size;
+  unsigned assoc;
+};
+
+#endif // CACHE_H
diff --git a/sid/component/cache/cacheutil.cxx b/sid/component/cache/cacheutil.cxx
new file mode 100644 (file)
index 0000000..f944fad
--- /dev/null
@@ -0,0 +1,355 @@
+// cacheutil.cxx -- Helper classes for a generic memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "cacheutil.h"
+
+bool
+std::operator== (const cache_tag& tag, const cache_line& line)
+{
+  return (line.valid_p () && tag == line.tag ());
+}
+
+bool
+std::operator== (const cache_line& line, const cache_tag& tag)
+{
+  return (line.valid_p () && tag == line.tag ());
+}
+
+cache_line::cache_line (const cache_line& other)
+{
+  size = other.size;
+  valid_bit = other.valid_bit;
+  dirty_bit = other.dirty_bit;
+  lock_bit = other.lock_bit;
+  atag = other.atag;
+  data = new byte [size];
+  memcpy (data, other.data, size);
+}
+
+cache_line&
+cache_line::operator= (const cache_line& other)
+{
+  if (this != &other)
+    {
+      // Beware of self-assignment.
+      size = other.size;
+      valid_bit = other.valid_bit;
+      dirty_bit = other.dirty_bit;
+      lock_bit = other.lock_bit;
+      atag = other.atag;
+      delete [] data;
+      data = new byte [size];
+      memcpy (data, other.data, size);
+    }
+  return *this;
+}
+
+void
+cache_line::dump () const
+{
+  cerr << "  ";
+
+  if (dirty_p ())  cerr << 'M'; else cerr << '-';
+  if (valid_p ())  cerr << 'V'; else cerr << '-';
+  if (locked_p ()) cerr << 'L'; else cerr << '-';
+
+  cerr << "  " << hex << setw (4) << setfill ('0') << atag << "\t";
+  for (unsigned i = 0; i < size; i++)
+    cerr << setw (2) << setfill ('0') << static_cast<unsigned> (data[i]);
+
+  cerr << dec << endl;
+}
+
+cache_line::cache_line (unsigned line_size)
+  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (0)
+{
+  data = new byte[line_size];
+  memset (data, 0, line_size);
+}
+
+cache_line::cache_line (unsigned line_size, cache_tag t)
+  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (t)
+{
+  data = new byte[line_size];
+  memset (data, 0, line_size);
+}
+
+cache_line::cache_line (unsigned line_size, cache_tag t, vector<byte> initial_data)
+  :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (t)
+{
+  assert (initial_data.size () == line_size);
+  data = new byte[line_size];
+  for (unsigned i = 0; i < line_size; i++)
+    data[i] = initial_data[i];
+}
+
+cache_line::~cache_line ()
+{
+  delete [] data;
+}
+
+void
+cache_line::dirty ()
+{
+  dirty_bit = true;
+}
+
+void
+cache_line::clean ()
+{
+  dirty_bit = false;
+}
+
+void
+cache_line::validate ()
+{
+  valid_bit = true;
+}
+
+void
+cache_line::invalidate ()
+{
+  valid_bit = false;
+}
+
+void
+cache_line::lock ()
+{
+  lock_bit = true;
+}
+
+void
+cache_line::unlock ()
+{
+  lock_bit = false;
+}
+
+cache_tag
+cache_line::tag () const
+{
+  return atag;
+}
+
+bool
+cache_line::dirty_p () const
+{
+  return dirty_bit;
+}
+
+bool
+cache_line::valid_p () const
+{
+  return valid_bit;
+}
+
+bool
+cache_line::locked_p () const
+{
+  return lock_bit;
+}
+
+cache_set::cache_set (unsigned line_size, unsigned nlines, cache_replacement_algorithm& alg)
+  :replacer (alg)
+{
+  lines.resize (nlines);
+  for (iterator_t it = lines.begin(); it != lines.end (); it++)
+    *it = new cache_line (line_size);
+}
+
+cache_set::~cache_set ()
+{
+  for (iterator_t it = lines.begin (); it != lines.end (); it++)
+    delete *it;
+}
+
+unsigned
+cache_set::num_lines () const
+{
+  return lines.size ();
+}
+
+cache_line&
+cache_set::get_line (unsigned i) const
+{
+  return *lines[i];
+}
+
+void
+cache_set::set_line (unsigned i, const cache_line line)
+{
+  *lines[i] = line;
+}
+
+cache_line&
+cache_set::find (const cache_tag& tag, bool& hit)
+{
+  static cache_line dummy(0);
+
+  // Scan the lines in this set for tag. Might as well be linear; the
+  // order of associativity will be small.
+
+  for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
+    if (tag == *(*it))
+      {
+       hit = true;
+       replacer.update (*this, *(*it));
+       return *(*it);
+      }
+  hit = false;
+  return dummy;
+}
+
+void
+cache_set::invalidate ()
+{
+  for (iterator_t it = lines.begin (); it != lines.end (); it++)
+    (*it)->invalidate ();
+}
+
+bool
+cache_set::vacancy_p () const
+{
+  for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
+    if (!(*it)->locked_p ())
+      return true;
+
+  return false;
+}
+    
+void
+cache_set::expunge_line (cache_line& line)
+{
+  line.unlock ();
+  line.clean ();
+  line.invalidate ();
+}
+
+void
+cache_set::replace_line (cache_line& old_line, cache_line new_line)
+{
+  return replacer.replace (*this, old_line, new_line);
+}
+
+void
+cache_set::dump () const
+{
+  for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
+    (*it)->dump ();
+}
+
+cache::cache (unsigned cache_size, unsigned line_size, unsigned assoc,
+             cache_replacement_algorithm& replacer)
+{
+  assert (power_of_two_p (line_size));
+  assert (cache_size >= line_size);
+
+  // The cache size must be an even multiple of the line size.
+  assert ((cache_size % line_size) == 0);
+
+  int num_lines = cache_size / line_size;
+  if (assoc > 0)
+    assert (num_lines % assoc == 0 && assoc < num_lines);
+  
+  // The number of sets.  
+  // If the cache is fully associative, there is only one set.
+  int num_sets = (assoc == 0) ? 1 : (num_lines / assoc);
+  sets.resize (num_sets);
+
+  // The number of lines per set.
+  // If the cache is fully associative, there is one set with as many
+  // lines as there are in the cache.
+  int lines_per_set = (assoc == 0) ? num_lines : assoc;
+  for (iterator_t it = sets.begin (); it != sets.end (); it++)
+    *it = new cache_set (line_size, lines_per_set, replacer);
+  
+  num_non_tag_bits = log2 (line_size);
+
+  // suitable defaults
+  hash_params.mask = 0x3fe0;
+  hash_params.shift = 5;
+}
+
+cache::~cache ()
+{
+  for (unsigned i = 0; i < sets.size (); i++)
+    delete sets[i];
+}
+
+cache_tag
+cache::addr_to_tag (const sid::host_int_4& addr) const
+{
+  return addr >> num_non_tag_bits;
+}
+
+sid::host_int_4
+cache::tag_to_addr (const cache_tag& tag) const
+{
+  return tag << num_non_tag_bits;
+}
+
+cache_line&
+cache::find (cache_tag tag, bool& hit)
+{
+  unsigned index = hash_fn (tag);
+  return sets[index]->find (tag, hit);
+}
+
+int
+cache::num_sets ()
+{
+  return sets.size ();
+}
+
+bool
+cache::vacancy_p (const sid::host_int_4& addr) const
+{
+  unsigned index = hash_fn (addr_to_tag (addr));
+  return sets[index]->vacancy_p ();
+}
+
+void
+cache::invalidate ()
+{
+  for (iterator_t it = sets.begin (); it != sets.end(); it++)
+    (*it)->invalidate ();
+}
+
+// Remove a line from the cache.
+void
+cache::expunge (cache_line& line)
+{
+  unsigned index = hash_fn (line.tag ());
+  sets[index]->expunge_line (line);
+}
+
+// Replace a line in the cache with 'new_line'.  If the expelled
+// line is dirty, set 'old_line' to it and return true, otherwise
+// false.
+void
+cache::replace (cache_line& old_line, cache_line new_line)
+{
+  unsigned index = hash_fn (new_line.tag ());
+  return sets[index]->replace_line (old_line, new_line);
+}
+
+unsigned
+cache::hash_fn (const cache_tag& tag) const
+{
+  sid::host_int_4 addr = tag_to_addr (tag);
+  return (addr & hash_params.mask) >> hash_params.shift;
+}
+
+void
+cache::dump () const
+{
+  unsigned i = 0;
+  for (const_iterator_t it = sets.begin (); it != sets.end (); it++, i++)
+    {
+      cerr << "set " << i << endl;
+      (*it)->dump ();
+    }
+}
diff --git a/sid/component/cache/cacheutil.h b/sid/component/cache/cacheutil.h
new file mode 100644 (file)
index 0000000..7f549c1
--- /dev/null
@@ -0,0 +1,225 @@
+// cacheutil.h -- Helper classes for a generic memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef CACHEUTIL_H
+#define CACHEUTIL_H
+
+#include <vector>
+#include <sidtypes.h>
+
+#include "log2.h"
+
+typedef sid::host_int_4 cache_tag;
+typedef sid::host_int_1 byte;
+
+// The cache_line class represents a line in a cache:
+
+// +-------+-----+----------------+ M = modified (dirty) bit
+// | M V L | tag |     data       | V = valid bit
+// +-------+-----+----------------+ L = lock bit
+//           byte 0              N
+
+class cache_line
+{
+public:
+  cache_line (unsigned line_size);
+  cache_line (unsigned line_size, cache_tag tag);
+  cache_line (unsigned line_size, cache_tag tag, vector <byte> intial_data);
+  cache_line (const cache_line&);
+  cache_line& operator= (const cache_line&);
+  ~cache_line ();
+
+  // Get the line's tag.
+  cache_tag tag () const;
+
+  // Mark the line dirty or clean.
+  void dirty ();
+  void clean ();
+
+  // Mark the line valid or invalid.
+  void validate ();
+  void invalidate ();
+
+  // Lock or unlock the line.
+  void lock ();
+  void unlock ();
+
+  // Is the line dirty?
+  bool dirty_p () const;
+
+  // Is the line valid?
+  bool valid_p () const;
+
+  // Is the line locked?
+  bool locked_p () const;
+
+  // Insert a datum into the line, starting at byte offset.
+  template <typename DataType>
+  void insert (unsigned offset, DataType new_data)
+  {
+    assert (offset + sizeof (new_data) <= size);
+    typename DataType::value_type mem_image = new_data.target_memory_value ();
+    memcpy (& data[offset], & mem_image, sizeof (new_data));
+    dirty_bit = true;
+  }
+
+  // Extract a datum from the line, starting at byte offset.
+  template <typename DataType>
+  void extract (unsigned offset, DataType& new_data) const
+  {
+    assert (offset + sizeof (new_data) <= size);
+    typename DataType::value_type mem_image;
+    memcpy (& mem_image, & data[offset], sizeof (new_data));
+    new_data.set_target_memory_value (mem_image);
+  }
+
+  // Dump a line in human readable form to cout.
+  void dump () const;
+
+private:
+  unsigned size;
+  bool valid_bit;
+  bool dirty_bit;
+  bool lock_bit;
+  byte *data;
+  cache_tag atag;
+};
+
+// Allow cache tags and a line's cache tag to be compared directly.
+
+bool std::operator== (const cache_tag&, const cache_line&);
+bool std::operator== (const cache_line&, const cache_tag&);
+
+
+// A class from which all replacement algorithms should be derived.
+
+class cache_set;
+class cache_replacement_algorithm
+{
+public:
+  // Place new_line in a cache slot. Point old_line to the existing line.
+  // Return true if successful, false otherwise.
+  virtual void replace (cache_set& cset, cache_line& old_line, cache_line new_line) = 0;
+
+  // Update state (for example, treating LRU bits), if required.
+  virtual void update (cache_set& cset, cache_line& accessed_line) {}
+};
+
+
+// The cache_set class represents a set of cache_lines.  For a 2-way
+// associative cache, there will be just two lines in the set.
+
+class cache_set
+{
+public:
+  cache_set (unsigned line_size, unsigned nlines,
+            cache_replacement_algorithm& alg);
+  ~cache_set ();
+  // Try to find a line in the cache with a matching tag. 
+  // If found, set "hit" to true and return a ref to the line.
+  // Otherwise, set "hit" to false.
+  virtual cache_line& find (const cache_tag& tag, bool& hit);
+
+  // Invalidate the entire set.
+  void invalidate (); 
+
+  // Is there any vacancy for a new line?
+  bool vacancy_p () const;
+
+  // Remove a line from the set.
+  void expunge_line (cache_line& line);
+
+  // Replace a line in the set with new_line.
+  // Return false if the line cannot be placed, true otherwise.
+  void replace_line (cache_line& old_line, cache_line new_line);
+
+  // Return the number of lines in the set.
+  unsigned num_lines () const;
+
+  // Get a cache line from slot `i' of the set.
+  cache_line& get_line (unsigned i) const;
+
+  // Place a cache line into slot `i' of the set.
+  void set_line (unsigned i, const cache_line line);
+
+  // Dump diagnostics to cerr.
+  virtual void dump () const;
+
+private:
+  cache_replacement_algorithm& replacer;
+  vector <cache_line*> lines;
+  typedef vector <cache_line*>::iterator iterator_t;
+  typedef vector <cache_line*>::const_iterator const_iterator_t;
+};
+
+\f
+// The cache class represents the complete cache as a series of
+// cache_sets.  For a fully-associative cache, there will be one set
+// with many lines.  For a direct mapped cache, there will be many
+// sets of single lines.  Provide high-level methods for the user.
+
+// The constructor builds a cache cache_size bytes in size and of the
+// specified associativity.  0=fully assoc., 1=direct mapped, 2=2-way,
+// etc.  The replacement algorithm is user-provided.
+
+class cache
+{
+public:
+  cache (unsigned cache_size, unsigned line_size,
+        unsigned assoc, cache_replacement_algorithm& replacer);
+  ~cache ();
+
+  // Calculate a tag.
+  cache_tag addr_to_tag (const sid::host_int_4& addr) const;
+
+  // Perform the inverse operation.
+  sid::host_int_4 tag_to_addr (const cache_tag& tag) const;
+  
+  // Find a line, given a tag.  If found, set hit to true and return it.
+  // Otherwise, set hit to false.
+  cache_line& find (cache_tag tag, bool& hit);
+
+  // Remove a line from the cache.
+  void expunge (cache_line& line);
+
+  // Vacancy in the cache?
+  bool vacancy_p (const sid::host_int_4& addr) const;
+
+  // Replace a line in the cache with 'new_line'.  If the expelled
+  // line is dirty, set 'old_line' to it and return true, otherwise
+  // false.
+  void replace (cache_line& old_line, cache_line new_line);
+
+  // Invalidate the entire cache.
+  void invalidate ();
+
+  // The number of sets in the cache.
+  int num_sets ();
+
+  // Dump the entire cache's state.
+  void dump () const;
+
+  // index = (addr & mask) >> shift
+  struct
+  {
+    sid::host_int_4 mask;
+    unsigned shift;
+  } hash_params;
+
+private:
+  // Compute the index into the cache.
+  unsigned hash_fn (const cache_tag& tag) const;
+
+  // The number of non-tag bits in an address.
+  unsigned num_non_tag_bits;
+
+  vector <cache_set*> sets;
+  typedef vector <cache_set*>::iterator iterator_t;
+  typedef vector <cache_set*>::const_iterator const_iterator_t;
+};
+
+#endif // CACHEUTIL_H
diff --git a/sid/component/cache/hw-cache.txt b/sid/component/cache/hw-cache.txt
new file mode 100644 (file)
index 0000000..bd7b2b6
--- /dev/null
@@ -0,0 +1,207 @@
+* Name
+  hw-cache-basic
+
+* Synopsis
+  This component models a variety of memory cache designs.
+
+  Buses: upstream
+  Accessors: downstream
+  Pins: report! flush invalidate invalidate-all prefetch lock unlock
+  Attributes: associativity cache-size line-size write-through?
+       write-allocate? hash-bit-mask hash-shift-amount
+       flushes replacements read-hit-rate write-hit-rate
+       read-accesses write-accesses misaligned-reads
+       misaligned-writes collect-statistics? report-heading dump!
+
+  Library: libcache.la
+  Symbol name: cache_component_library
+
+* Functionality
+  - Modeling
+
+     * This component models a memory cache suitable for use at
+       different levels of the memory hierarchy.  It provides a bus
+       interface and connects to another bus, providing a transparent
+       pass-through.  In this documentation, "CPU" and "main memory"
+       are synonymous for "upstream bus" and "downstream bus", as this
+       is the most common usage (but not the only possible).
+
+    * The parameters of the cache are a matter of configuration.  At
+      instantiation time, the following parameters are specified:
+
+           + cache size (in kilobytes)
+             { 8, 16, 32, 64, 128, 256, 512 }
+           + line size (in bytes)
+             { 16, 32, 64, 128 }
+           + associativity
+             { "direct", "full", "2-way", "4-way" }
+           + replacement policy (for N-way and fully associative)
+             { "lru", "fifo", "random" }
+
+      For a 16kb cache with a line size of 32 bytes, 2-way set
+      associativity and a "least recently used" (LRU) replacement
+      policy, the component name is "hw-cache-2way/16kb/32/lru".
+
+      For direct mapped caches, replacement policies are not
+      applicable and should be omitted from the component name.  For
+      example: "hw-cache-direct/64kb/16".  This particular 64KB
+      direct-mapped cache configuration is also known by the type name
+      of "hw-cache-basic".
+
+      Other parameters affecting the operation of the cache are
+      controlled by modifying attributes (see Behaviors).
+
+  - Behaviors
+    * Tag calculation
+      The size of a tag is dynamically computed based on the line
+      size.  Unlike physical caches which economise on the number of
+      tag bits to reduce hardware costs, the model uses a full
+      address, but discards the redundant bits that can be inferred by
+      a bytes position in the cache line.  For example, a 32 (2^5)
+      byte line uses 27 bits for the tag.
+
+    * Hash algorithm
+      A simple hashing algorithm is used to select a set from a target
+      address.  The algorithm uses values from the "hash-bit-mask" and
+      "hash-shift-amount" attributes to compute:
+               
+               index = (address & mask) >> shift_amount;
+      
+      These two values must be chosen carefully to ensure good cache
+      utilisation.  In particular, the "all-ones" value of "mask"
+      should not exceed the number of sets in the cache.
+
+    * Misaligned accesses
+      The component does not handle memory accesses that are not
+      aligned on the natural boundary of the data being referenced.
+      In such cases, the cache is bypassed and memory is accessed
+      directly.
+
+    * Write strategy
+      When a write is made to the cache, the "write-through?"
+      attribute determines if the data will be simultaneously written
+      to the memory.  Otherwise, writes will only be made to the cache
+      and will not be synchronised with main memory until the line is
+      flushed due to line replacement or an explicit flush (see
+      Flushing).
+
+      In the case of a write miss, the "write-allocate?" attribute
+      specifies the component's action.  If this attribute is set to
+      "yes", then a miss will cause the missed line to be loaded into
+      the cache in anticipation of future references.
+
+    * Prefetching
+      The component supports prefetching of data into the cache by
+      driving the "prefetch" pin with an address.  If, due to the line
+      replacement policy, the prefetch cannot be performed, this
+      operation has no effect.
+
+    * Flushing
+      If dirty lines are flushed from the cache, the component will
+      ensure that their contents are synchronized with main memory.
+      Some architectures provide a facility for explicitly flushing a
+      line to memory.  For this purpose, the component provides a
+      "flush" pin that can be driven with an address.  If the address
+      falls on a line that is present and dirty, it will be flushed to
+      memory and marked as not dirty.
+
+    * Invalidating
+      Lines in the cache that contain accurate contents are marked as
+      valid.  Some architectures provide a facility for explicitly
+      marking a line as invalid so that future accesses will cause a
+      new memory access.  For this purpose, the component provides an
+      "invalidate" pin that can be driven with an address.  If the
+      address falls on a line that is present, it will be invalidated.
+      No consideration is made for dirty lines, so a line should be
+      flushed before being invalidated.  The entire cache can be
+      invalidated by driving the "invalidate-all" pin.
+
+    * Line locking
+      The component supports locking lines in the cache to prevent
+      them from being removed to accommodate more recently referenced
+      lines.  A line can be locked by driving the "lock" pin with any
+      address that falls on the line.  Subsequently, a line can be
+      unlocked by driving the "unlock" pin.
+
+    * Statistics gathering
+      The component gathers statistics for a number of significant
+      events and records them in read-only attributes.  The collection
+      of statistics may be disabled with the "collect-statistics?"
+      attribute.
+
+    * Statistics reporting
+      The component will write a summary report of the statistics it
+      collects to standard error when the "report!" pin is driven.
+      The "report heading" attribute value, prepended to the report,
+      allows reports from multiple caches to be distinguished.
+
+  - SID conventions
+    * This is a functional component.
+    * It presents attributes in the "setting" and "register" categories.
+
+* Environment
+  - Related components
+    * This component is typically used as a cache between a CPU and
+      main memory.  A sample configuration fragment is:
+
+        new hw-cpu-arm7t cpu
+        new hw-cache-basic cache
+        connect-bus cpu insn-memory cache upstream
+        connect-bus cpu data-memory cache upstream
+       connect-bus cache downstream mem read-write-port
+
+    * More extensive modeling of the memory hierarchy could be
+      achieved by daisy-chaining two caches:
+
+        new hw-cpu-arm7t cpu
+        new hw-cache-basic l1-cache
+        new hw-cache-basic l2-cache
+        connect-bus cpu insn-memory l1-cache upstream
+        connect-bus cpu data-memory l1-cache upstream
+       connect-bus l1-cache downstream l2-cache upstream
+       connect-bus l2-cache downstream mem read-write-port
+
+    * The cache can operate using virtual or physical addresses.  This
+      is determined by the location of the cache in the memory
+      hierarchy.  The cache can manage physical addresses by placing
+      it "downstream" from an MMU or bus mapper (see hw-mapper-basic).
+
+* SID interface reference
+  - low level:
+    * pins
+      - report! | input | any | statistics reporting
+      - flush | input | any | flushing
+      - invalidate | input | any | invalidating
+      - invalidate-all | input | any | invalidating
+      - prefetch | input | any | prefetching
+      - lock | input | any | line locking
+      - unlock | input | any | line locking
+    * buses
+      - upstream | any address | any access | pass-through
+    * accessors
+      - downstram | any address | any access | pass-through
+    * attributes
+      - associativity | settings | string | n/a | configuration
+      - cache-size | settings | numeric | n/a | configuration
+      - line-size | settings | numeric | n/a | configuration
+      - hash-bit-mask | setting | numeric | 0xf | configuration
+      - hash-shift-amount | setting | 0..31 | 0 | configuration
+      - write-through? | setting | boolean | false | write strategy
+      - write-allocate? | setting | boolean | false | write strategy
+      - read-accesses | register | numeric | 0 | statistics gathering
+      - write-accesses | register | numeric | 0 | statistics gathering
+      - misaligned-reads | register | numeric | 0 | statistics gathering
+      - misaligned-writes | register | numeric | 0 | statistics gathering
+      - flushes | register | numeric | 0 | statistics gathering
+      - replacements | register | numeric | 0 | statistics gathering
+      - read-hit-rate | register | %age string | 0% | statistics gathering
+      - write-hit-rate | register | %age string | 0% | statistics gathering
+      - collect-statistics? | setting | boolean | true | statistics gathering
+      - report-heading | setting | string | cache profile report | stats g.
+      - dump! | setting | empty string | empty | internal diagnostics
+
+* References
+
+  ``Computer Architecture: A Quantitative Approach'', Hennessy & Patterson.
+  ``Advanced Microprocessors'', D. Tabak.
+  ``UNIX Systems for Modern Architectures'', C. Schimmel. 
diff --git a/sid/component/cache/log2.h b/sid/component/cache/log2.h
new file mode 100644 (file)
index 0000000..74c7a99
--- /dev/null
@@ -0,0 +1,39 @@
+// log2.h -- Utility functions for power of two values. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef LOG2_H
+#define LOG2_H
+
+// Is V a power of two (ie. 32, 64)?
+
+template <typename V>
+bool power_of_two_p (const V& v1)
+{
+  int count = 0;
+  V v2(1);
+
+  for (int i = 0; i < 8 * sizeof (V); i++)
+    if (v1 & (v2 << i))
+      count++;
+
+  // Only one bit was set in v1.
+  return (count == 1);
+}
+
+// Compute log2 (V).
+
+template <typename V>
+int log2 (const V& v1)
+{
+  assert (power_of_two_p (v1));
+
+  V v2(1);
+  for (int i = 0; i < 8 * sizeof (V); i++)
+    if (v1 & (v2 << i))
+      return i;
+}
+
+#endif // LOG2_H
index 07d5d00..367b905 100755 (executable)
@@ -3174,7 +3174,7 @@ subdirs="cfgroot tcl audio cgen-cpu timers"
 
 
 
-make_subdirs="consoles gdb gloss glue ide interrupt lcd loader mapper memory mmu parport profiling rtc sched uart testsuite"
+make_subdirs="cache consoles gdb gloss glue ide interrupt lcd loader mapper memory mmu parport profiling rtc sched uart testsuite"
 
 
 trap '' 1 2 15
@@ -3279,6 +3279,7 @@ ac_given_srcdir=$srcdir
 ac_given_INSTALL="$INSTALL"
 
 trap 'rm -fr `echo "Makefile testsuite/Makefile tconfig.h:tconfig.in siddoc
+       cache/Makefile
        consoles/Makefile
        gdb/Makefile
        gloss/Makefile
@@ -3425,6 +3426,7 @@ EOF
 cat >> $CONFIG_STATUS <<EOF
 
 CONFIG_FILES=\${CONFIG_FILES-"Makefile testsuite/Makefile tconfig.h:tconfig.in siddoc
+       cache/Makefile
        consoles/Makefile
        gdb/Makefile
        gloss/Makefile
index 92c1bf0..d0ea695 100644 (file)
@@ -91,12 +91,13 @@ AC_CONFIG_SUBDIRS([cfgroot tcl audio cgen-cpu timers])
 
 dnl All other component subdirectories should be listed here, so "make"
 dnl can recursively descend there - see "Makefile.am".
-make_subdirs="consoles gdb gloss glue ide interrupt lcd loader mapper memory mmu parport profiling rtc sched uart testsuite"
+make_subdirs="cache consoles gdb gloss glue ide interrupt lcd loader mapper memory mmu parport profiling rtc sched uart testsuite"
 AC_SUBST(make_subdirs)
 
 dnl List all component subdirectory files not covered by AC_CONFIG_SUBDIRS
 dnl that need autoconf @substitution@.
 AC_OUTPUT([Makefile testsuite/Makefile tconfig.h:tconfig.in siddoc
+       cache/Makefile
        consoles/Makefile
        gdb/Makefile
        gloss/Makefile
index 11bbcc3..d252607 100644 (file)
@@ -1,3 +1,21 @@
+2001-06-15  Ben Elliston  <bje@redhat.com>
+
+       * sidcomp.cache/cache.exp: New test case.
+       * sidcomp.cache/cachedocs.exp: Ditto.
+       * sidcomp.cache/cachemonkey.exp: Ditto.
+       * sidcomp.cache/coherency.exp: Ditto.
+       * sidcomp.cache/fifo.exp: Ditto.
+       * sidcomp.cache/flush.exp: Ditto.
+       * sidcomp.cache/lock.exp: Ditto.
+       * sidcomp.cache/lru.exp: Ditto.
+       * sidcomp.cache/misaligned.exp: Ditto.
+       * sidcomp.cache/prefetch.exp: Ditto.
+       * sidcomp.cache/random.exp: Ditto.
+       * sidcomp.cache/types.exp: Ditto.
+       * sidcomp.cache/utils.exp: Ditto.
+       * sidcomp.cache/writealloc.exp: Ditto.
+       * sidcomp.cache/writethru.exp: Ditto.
+
 2001-06-13  Ben Elliston  <bje@redhat.com>
 
        * lib/docs.exp (doc_test): Pass $compname to doc_exists.
diff --git a/sid/component/testsuite/sidcomp.cache/cache.exp b/sid/component/testsuite/sidcomp.cache/cache.exp
new file mode 100644 (file)
index 0000000..22b5b9c
--- /dev/null
@@ -0,0 +1,113 @@
+# cache.exp -*- Tcl -*-
+# Basic testing for the cache component. 
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid configuration"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+pass $test
+
+set test "sid startup"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "all pins are present"
+sid_assert_includes_all "sid::component::pin_names $victim" \
+       {report! flush invalidate invalidate-all prefetch lock unlock}
+
+set test "all attributes are present"
+sid_assert_includes_all "sid::component::attribute_names $victim" \
+       {associativity cache-size line-size write-through? \
+        write-allocate? hash-bit-mask hash-shift-amount \
+        flushes replacements read-hit-rate write-hit-rate \
+        read-accesses write-accesses misaligned-reads \
+        misaligned-writes collect-statistics? report-heading dump!}
+
+set test "upstream bus is present"
+sid_assert_includes_all "sid::component::bus_names $victim" upstream
+
+set test "downstream accessor is present"
+sid_assert_includes_all "sid::component::accessor_names $victim" downstream
+
+foreach attr {read-accesses write-accesses misaligned-reads \
+       misaligned-writes flushes replacements} {
+    set test "$attr initialised to 0"
+    set value [get_attr $attr]
+    if {$value == 0} { pass $test } else { fail $test }
+}
+
+foreach attr {read-hit-rate write-hit-rate} {
+    set test "$attr is initialised to 0%"
+    set value [get_attr $attr]
+    if {$value == "0%"} { pass $test } else { fail $test }
+}
+
+proc assert_attr_default {attr default} {
+    global victim
+    set test "$attr is set for hw-cache-basic"
+    set value [get_attr $attr]
+    if {$value == $default} { pass $test } else { fail $test }
+}
+
+assert_attr_default associativity direct-mapped
+assert_attr_default cache-size 16384
+assert_attr_default line-size 32
+assert_attr_default write-through? no
+assert_attr_default write-allocate? no
+assert_attr_default collect-statistics? yes 
+assert_attr_default report-heading "cache profile report"
+
+# now the real meaty tests
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+# read a byte from 0x100
+# this should cause a cache miss
+
+set test "read a byte from 0x100"
+clear_miss_flag
+set prior(reads) [get_attr read-accesses]
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_miss
+assert_variant read-accesses $prior(reads)
+
+set test "read a byte from 0x100"
+clear_miss_flag
+set prior(reads) [get_attr read-accesses]
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_hit
+assert_variant read-accesses $prior(reads)
+
+set test "read another byte on the same line as 0x100"
+clear_miss_flag
+set prior(reads) [get_attr read-accesses]
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x101"]
+assert_hit
+assert_variant read-accesses $prior(reads)
+
+# read another address that hashes to the same line index
+set test "read from 0x4100 which hashes to the same line"
+clear_miss_flag
+set prior(reads) [get_attr read-accesses]
+set prior(replacements) [get_attr replacements]
+set prior(flushes) [get_attr flushes]
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4100"]
+assert_miss
+assert_variant read-accesses $prior(reads)
+assert_variant replacements $prior(replacements)
+assert_invariant flushes $prior(flushes)
diff --git a/sid/component/testsuite/sidcomp.cache/cachedocs.exp b/sid/component/testsuite/sidcomp.cache/cachedocs.exp
new file mode 100644 (file)
index 0000000..8eb29a1
--- /dev/null
@@ -0,0 +1,3 @@
+load_lib "docs.exp"
+
+doc_test cache hw-cache-basic
diff --git a/sid/component/testsuite/sidcomp.cache/cachemonkey.exp b/sid/component/testsuite/sidcomp.cache/cachemonkey.exp
new file mode 100644 (file)
index 0000000..32e72a6
--- /dev/null
@@ -0,0 +1,6 @@
+# Run a monkey test on the components in this component library. 
+
+load_lib "monkey.exp"
+
+proc state_safe_p {} { return 0 }
+monkey_test hw-cache-basic cache_component_library libcache.la
diff --git a/sid/component/testsuite/sidcomp.cache/coherency.exp b/sid/component/testsuite/sidcomp.cache/coherency.exp
new file mode 100644 (file)
index 0000000..4118291
--- /dev/null
@@ -0,0 +1,29 @@
+# coherency.exp -*- Tcl -*-
+# Basic testing for the LRU replacement policy.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+set test "sid startup"
+sid_config_component_etc_test_with_tracing "coherency.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic" \
+       "load [sid_find_file libmemory.la] mem_component_library
+new hw-memory-ram/rom-basic mem
+set mem size 2048
+set real-victim write-through? no
+connect-bus real-victim downstream mem read-write-port"
+
+if {[sid_start "coherency.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "cache coherency"
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x100 0x55"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok" || [format %x [lindex $result 1]] != "55" } { fail $test; return }
+pass $test
diff --git a/sid/component/testsuite/sidcomp.cache/fifo.exp b/sid/component/testsuite/sidcomp.cache/fifo.exp
new file mode 100644 (file)
index 0000000..28880ed
--- /dev/null
@@ -0,0 +1,77 @@
+# fifo.exp -*- Tcl -*-
+# Basic testing for the first-in first-out (FIFO) replacement policy.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-4way/16kb/32/fifo"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+foreach addr {0x100 0x4100 0x8100 0xc100} {
+    set test "read byte from $addr"
+    clear_miss_flag
+    set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus $addr"]
+    assert_miss
+}
+
+# These should still hit, since there are four lines per set.
+foreach addr {0x100 0x4100 0x8100 0xc100} {
+    set test "read byte again from $addr"
+    clear_miss_flag
+    set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus $addr"]
+    assert_hit
+}
+
+# Out of lines in the set!
+set test "read byte from 0x10100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x10100"]
+assert_miss
+
+# This line should still be present, since it isn't old.
+set test "line for 0x8100 is still in the cache"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x8100"]
+assert_hit
+
+# This is the oldest line in the set and should have been removed.
+set test "line for 0x100 has been removed from the cache"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_miss
+
+# This line should still be present.
+set test "line for 0x8100 is still in the cache"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x8100"]
+assert_hit
+
+# Now load another byte, which will flush the 0x4100 line.
+set test "read byte from 0x14100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x14100"]
+assert_miss
+
+# Check that 0x8100 has been removed.
+set test "line for 0x8100 has been removed from the cache"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x8100"]
+assert_miss
diff --git a/sid/component/testsuite/sidcomp.cache/flush.exp b/sid/component/testsuite/sidcomp.cache/flush.exp
new file mode 100644 (file)
index 0000000..018e75e
--- /dev/null
@@ -0,0 +1,66 @@
+# flush.exp -*- Tcl -*-
+# Testing of flush operations.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+set test "read a byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_miss
+
+set test "write a byte to 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x100 0x55"]
+assert_hit
+
+set test "flush dirty line"
+clear_miss_flag
+set flush_pin [sid_cmd "sid::component::find_pin $victim flush"]
+sid_cmd "sid::pin::driven_h4 $flush_pin 0x100"
+assert_miss
+
+set test "flush clean line"
+clear_miss_flag
+sid_cmd "sid::pin::driven_h4 $flush_pin 0x100"
+assert_hit
+
+# Test flushes of modified cache lines to memory.
+# Populate a known line; modify it; read from an address that collides
+# with the line index and causes a flush.
+
+set test "read a line"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x500"]
+assert_miss
+
+set test "make a line dirty"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x500 0x55"]
+assert_hit
+
+set test "displacing a dirty line causes bus activity"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4500"]
+assert_miss
diff --git a/sid/component/testsuite/sidcomp.cache/lock.exp b/sid/component/testsuite/sidcomp.cache/lock.exp
new file mode 100644 (file)
index 0000000..28b06a8
--- /dev/null
@@ -0,0 +1,101 @@
+# lock.exp -*- Tcl -*-
+# Testing of the lock/unlock pins.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+# read a byte from 0x100 and make sure we get a miss
+set test "read a byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_miss
+
+# read a byte from 0x100 and make sure we get a hit
+set test "read another byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_hit
+
+# drive 0x100 down the lock pin
+set test "lock 0x100"
+set lock_pin [sid_cmd "sid::component::find_pin $victim lock"]
+sid_cmd "sid::pin::driven_h4 $lock_pin 0x100"
+pass $test
+
+set test "double lock"
+set lock_pin [sid_cmd "sid::component::find_pin $victim lock"]
+sid_cmd "sid::pin::driven_h4 $lock_pin 0x100"
+pass $test
+
+# read a byte from 0x100 and make sure we get a hit
+set test "read a byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_hit
+
+# read a byte from 0x4100 and make sure we get a miss
+set test "read a byte from 0x4100"
+clear_miss_flag
+sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4100"
+assert_miss
+
+# read a byte from 0x4100 and make sure we get another miss
+set test "read another byte from 0x4100"
+clear_miss_flag
+sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4100"
+assert_miss
+
+# read a byte from 0x100 and make sure we get a hit
+set test "read a byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_hit
+
+# drive 0x100 down the unlock pin
+set test "unlock 0x100"
+set unlock_pin [sid_cmd "sid::component::find_pin $victim unlock"]
+sid_cmd "sid::pin::driven_h4 $unlock_pin 0x100"
+pass $test
+
+set test "double unlock"
+set unlock_pin [sid_cmd "sid::component::find_pin $victim unlock"]
+sid_cmd "sid::pin::driven_h4 $unlock_pin 0x100"
+pass $test
+
+# read a byte from 0x4100 and make sure we get a miss
+set test "read a byte from 0x4100"
+clear_miss_flag
+sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4100"
+assert_miss
+
+# read a byte from 0x4100 and make sure we get a hit
+set test "read another byte from 0x4100"
+clear_miss_flag
+sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4100"
+assert_hit
+
+# ensure only one line replacement occured
+set test "replacements stat equals 2"
+set value [get_attr replacements]
+if {$value == 2} { pass $test } else { fail "$test ($value)" }
diff --git a/sid/component/testsuite/sidcomp.cache/lru.exp b/sid/component/testsuite/sidcomp.cache/lru.exp
new file mode 100644 (file)
index 0000000..ae4abbe
--- /dev/null
@@ -0,0 +1,53 @@
+# lru.exp -*- Tcl -*-
+# Basic testing for the LRU replacement policy.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-4way/16kb/32/lru"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+foreach addr {0x100 0x4100 0x8100 0xc100} {
+    set test "read byte from $addr"
+    clear_miss_flag
+    set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus $addr"]
+    assert_miss
+}
+
+# These should still hit, since there are four lines per set.
+foreach addr {0x100 0x4100 0x8100 0xc100} {
+    set test "read byte again from $addr"
+    clear_miss_flag
+    set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus $addr"]
+    assert_hit
+}
+
+# Out of lines in the set!
+set test "read byte from 0x10100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x10100"]
+assert_miss
+
+# This line should still be present, since it was used recently.
+set test "read byte from 0x8100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x8100"]
+assert_hit
diff --git a/sid/component/testsuite/sidcomp.cache/misaligned.exp b/sid/component/testsuite/sidcomp.cache/misaligned.exp
new file mode 100644 (file)
index 0000000..270ab47
--- /dev/null
@@ -0,0 +1,56 @@
+# misaligned.exp -*- Tcl -*-
+# Basic testing for the cache component. 
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+# read a 32-bit word from 0x101 (misaligned)
+set test "misaligned read from 0x101"
+clear_miss_flag
+set prior(reads) [get_attr read-accesses]
+set prior(writes) [get_attr write-accesses]
+set prior(misaligned-reads) [get_attr misaligned-reads]
+set prior(misaligned-writes) [get_attr misaligned-writes]
+set result [sid_cmd "sid::bus::read_h4_l4 $cache_bus 0x101"]
+assert_miss
+assert_variant read-accesses $prior(reads)
+assert_variant misaligned-reads $prior(misaligned-reads)
+assert_invariant write-accesses $prior(writes)
+assert_invariant misaligned-writes $prior(misaligned-writes)
+
+
+# write a 16-bit word from 0x105 (misaligned)
+set test "misaligned write to 0x105"
+clear_miss_flag
+set prior(reads) [get_attr read-accesses]
+set prior(writes) [get_attr write-accesses]
+set prior(misaligned-reads) [get_attr misaligned-reads]
+set prior(misaligned-writes) [get_attr misaligned-writes]
+set result [sid_cmd "sid::bus::write_h4_l2 $cache_bus 0x101 0x5555"]
+assert_miss
+assert_variant write-accesses $prior(writes)
+assert_variant misaligned-writes $prior(misaligned-writes) 
+assert_invariant read-accesses $prior(reads)
+assert_invariant misaligned-reads $prior(misaligned-reads)
+
diff --git a/sid/component/testsuite/sidcomp.cache/prefetch.exp b/sid/component/testsuite/sidcomp.cache/prefetch.exp
new file mode 100644 (file)
index 0000000..bc99b78
--- /dev/null
@@ -0,0 +1,44 @@
+# prefetch.exp -*- Tcl -*-
+# Testing of the prefetch pin.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+# drive 0x100 down the prefetch pin
+set prefetch_pin [sid_cmd "sid::component::find_pin $victim prefetch"]
+sid_cmd "sid::pin::driven_h4 $prefetch_pin 0x100"
+pass $test
+
+# read a byte from 0x100 and make sure we get a hit
+set test "read a byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+assert_hit
+
+# read a byte from 0x4100 and make sure we get a miss
+set test "read a byte from 0x4100"
+clear_miss_flag
+sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x4100"
+assert_miss
+
diff --git a/sid/component/testsuite/sidcomp.cache/random.exp b/sid/component/testsuite/sidcomp.cache/random.exp
new file mode 100644 (file)
index 0000000..9ec5ea5
--- /dev/null
@@ -0,0 +1,47 @@
+# random.exp -*- Tcl -*-
+# Basic testing for the random replacement policy.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-4way/16kb/32/fifo"
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+foreach addr {0x100 0x4100 0x8100 0xc100} {
+    set test "read byte from $addr"
+    clear_miss_flag
+    set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus $addr"]
+    assert_miss
+}
+
+# These should still hit, since there are four lines per set.
+foreach addr {0x100 0x4100 0x8100 0xc100} {
+    set test "read byte again from $addr"
+    clear_miss_flag
+    set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus $addr"]
+    assert_hit
+}
+
+# Out of lines in the set!
+set test "read byte from 0x10100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x10100"]
+assert_miss
diff --git a/sid/component/testsuite/sidcomp.cache/types.exp b/sid/component/testsuite/sidcomp.cache/types.exp
new file mode 100644 (file)
index 0000000..dbaec79
--- /dev/null
@@ -0,0 +1,44 @@
+# types.exp -*- Tcl -*-
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+foreach cache_size { 8 16 32 64 128 256 512 } {
+    foreach line_size { 16 32 64 128 } {
+       foreach assocy { direct full 2way 4way } {
+           foreach replacement_alg { lru fifo random } {
+               set typename  \
+                       "hw-cache-${assocy}/${cache_size}kb/${line_size}"
+               if {$assocy != "direct"} {
+                   append typename "/${replacement_alg}"
+               }
+               set test "sid configuration ($typename)"
+               sid_config_component_test_with_tracing "cache.conf" \
+                       "load [sid_find_file libcache.la] cache_component_library" $typename
+               pass $test
+               set test "sid startup ($typename)"
+               if {[sid_start "cache.conf"]} {
+                   pass $test
+                   set test "sid shutdown ($typename)"
+                   if {[sid_stop]} { pass $test } else { fail $test; return }
+               } else {
+                   fail $test
+               }
+           }
+       }
+    }
+}
+
+# Bad configurations
+foreach bad_type { hw-cache-foo hw-cache-direct/x/y/z hw-direct-10 } {
+    set test "bad component type name ($typename)"
+    sid_config_component_test_with_tracing "cache.conf" \
+           "load [sid_find_file libcache.la] cache_component_library" $bad_type
+    pass $test
+    set test "sid startup ($bad_type)"
+    if {[sid_start "cache.conf"]} {
+       fail $test
+       sid_stop
+    } else {
+       pass $test
+    }
+}
diff --git a/sid/component/testsuite/sidcomp.cache/utils.exp b/sid/component/testsuite/sidcomp.cache/utils.exp
new file mode 100644 (file)
index 0000000..a773551
--- /dev/null
@@ -0,0 +1,47 @@
+# utils.exp -*- Tcl -*-
+# Utility routines for the cache component testsuite
+#
+# Copyright (C) 2001 Red Hat
+
+proc get_attr {attr} {
+    global victim
+    return [sid_cmd "sid::component::attribute_value $victim $attr"]
+}
+
+proc miss_p {} { return [expr [sid_cmd "set thru"] == 1] }
+proc hit_p {} { return ![miss_p] }
+proc clear_miss_flag {} { sid_cmd "set thru 0" }
+
+# Assert that a cache access causes bus activity (ie. a miss).
+proc assert_miss {} { global test; if [miss_p] { pass "$test (miss)" } else { fail "$test (miss)" }}
+
+# Assert that a cache access causes bus activity (ie. a hit).
+proc assert_hit {} { global test; if [hit_p] { pass "$test (hit)" } else { fail "$test (hit)" }}
+
+# Assert that an attribute is variant (by delta).
+proc assert_variant {attr prior {delta 1}} {
+    global victim
+    set test "$attr attribute has been incremented"
+    set value [get_attr $attr]
+    if {[expr $prior + $delta] == $value} { pass $test } else { fail $test }
+}
+
+# Assert that an attribute is invariant.
+proc assert_invariant {attr prior} {
+    global victim
+    set test "$attr attribute is invariant"
+    set value [get_attr $attr]
+    if {$prior == $value} { pass $test } else { fail $test }
+}
+
+# Instrument $bus as a test bus.
+proc instrument_bus {bus} {
+    sid_cmd "if {[info exists hook_written]} { unset hook_written }"
+    sid_cmd "if {[info exists hook_read]} { unset hook_read }"
+    foreach endian {l b} {
+       foreach width {1 2 4 8} {
+           sid_cmd "set hook_read(h4,${endian}${width},$bus) { set thru 1 ; return {ok 0}}"
+           sid_cmd "set hook_written(h4,${endian}${width},$bus) { set thru 1 ; return ok}"
+       }
+    }
+}
diff --git a/sid/component/testsuite/sidcomp.cache/writealloc.exp b/sid/component/testsuite/sidcomp.cache/writealloc.exp
new file mode 100644 (file)
index 0000000..bc85c5f
--- /dev/null
@@ -0,0 +1,85 @@
+# writealloc.exp -*- Tcl -*-
+# Test the write allocate strategy.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+# Enable write allocate.
+
+set test "enable write allocate"
+set result [sid_cmd "sid::component::set_attribute_value $victim write-allocate? yes"]
+if {$result != "ok" } { fail $test; return }
+
+# Test write allocate by writing to a line which produces a miss.
+# Check to make sure that the line is then loaded.
+
+set test "write byte to 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x100 0x55"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_miss
+
+set test "read byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+set test "another write to 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x100 0x55"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+set test "another read from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+# Disable write allocate.  Now, writes that miss will go straight
+# through.  Thus, a subsequent read from the same address will "miss".
+
+set test "disable write allocate"
+set result [sid_cmd "sid::component::set_attribute_value $victim write-allocate? no"]
+if {$result != "ok" } { fail $test; return }
+
+set test "write byte to 0x500"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x500 0x55"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_miss
+
+set test "read byte from 0x500"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x500"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_miss
+
+set test "read byte from 0x500 again"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x500"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
diff --git a/sid/component/testsuite/sidcomp.cache/writethru.exp b/sid/component/testsuite/sidcomp.cache/writethru.exp
new file mode 100644 (file)
index 0000000..f7b82a3
--- /dev/null
@@ -0,0 +1,93 @@
+# writethru.exp -*- Tcl -*-
+# Test the write through strategy.
+#
+# Copyright (C) 2001 Red Hat, Inc.
+
+source $srcdir/$subdir/utils.exp
+
+set test "sid startup"
+sid_config_component_test_with_tracing "cache.conf" \
+        "load [sid_find_file libcache.la] cache_component_library" \
+        "hw-cache-basic"
+
+if {[sid_start "cache.conf"]} { pass $test } else { fail $test; return }
+
+set test "acquire upstream bus handle"
+set cache_bus [sid_cmd "sid::component::find_bus $victim upstream"]
+if {$cache_bus != ""} { pass $test } else { fail $test }
+
+set test "generate test bus for downstream"
+set mem_bus [sid_cmd "sid::bus::new"]
+if {$mem_bus == ""} { fail $test } else { pass $test }
+
+set test "connect test bus to cache"
+set result [sid_cmd "sid::component::connect_accessor $victim downstream $mem_bus"]
+if {$result == "ok"} { pass $test } else { fail $test }
+
+instrument_bus $mem_bus
+
+# Enable write through.
+
+set test "enable write through"
+set result [sid_cmd "sid::component::set_attribute_value $victim write-through? yes"]
+if {$result != "ok" } { fail $test; return }
+
+# Test write through by writing to a line which produces a hit.
+# Check to make sure that the memory bus is accessed.
+
+set test "read byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_miss
+
+set test "read byte from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+set test "write byte to 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x100 0x55"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_miss
+
+set test "read byte back from 0x100"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x100"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+# Now disable write through.
+
+set test "disable write through"
+set result [sid_cmd "sid::component::set_attribute_value $victim write-through? no"]
+if {$result != "ok" } { fail $test; return }
+
+# Test write through by writing to a line which produces a hit.
+# Check to make sure that no memory bus accesses are made.
+
+set test "read byte from 0x500"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x500"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_miss
+
+set test "read byte from 0x500"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x500"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+set test "write byte to 0x500"
+clear_miss_flag
+set result [sid_cmd "sid::bus::write_h4_l1 $cache_bus 0x500 0x55"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit
+
+set test "read byte back from 0x500"
+clear_miss_flag
+set result [sid_cmd "sid::bus::read_h4_l1 $cache_bus 0x500"]
+if {[lindex $result 0] != "ok"} { fail $test; return }
+assert_hit