From cee70916e2dc746fb8ec259f978737b8f8990f49 Mon Sep 17 00:00:00 2001 From: bje Date: Fri, 15 Jun 2001 04:19:50 +0000 Subject: [PATCH] Index: component/ChangeLog 2001-06-12 Ben Elliston * 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 * 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 * Makefile.am: New file. * Makefile.in: Generate. 2001-06-15 Ben Elliston * 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. --- sid/component/CATALOG | 5 +- sid/component/ChangeLog | 7 + sid/component/Makefile.in | 7 +- sid/component/cache/ChangeLog | 13 + sid/component/cache/Makefile.am | 18 + sid/component/cache/Makefile.in | 416 ++++++++++++ sid/component/cache/cache.cxx | 748 +++++++++++++++++++++ sid/component/cache/cache.h | 186 +++++ sid/component/cache/cacheutil.cxx | 355 ++++++++++ sid/component/cache/cacheutil.h | 225 +++++++ sid/component/cache/hw-cache.txt | 207 ++++++ sid/component/cache/log2.h | 39 ++ sid/component/configure | 4 +- sid/component/configure.in | 3 +- sid/component/testsuite/ChangeLog | 18 + sid/component/testsuite/sidcomp.cache/cache.exp | 113 ++++ .../testsuite/sidcomp.cache/cachedocs.exp | 3 + .../testsuite/sidcomp.cache/cachemonkey.exp | 6 + .../testsuite/sidcomp.cache/coherency.exp | 29 + sid/component/testsuite/sidcomp.cache/fifo.exp | 77 +++ sid/component/testsuite/sidcomp.cache/flush.exp | 66 ++ sid/component/testsuite/sidcomp.cache/lock.exp | 101 +++ sid/component/testsuite/sidcomp.cache/lru.exp | 53 ++ .../testsuite/sidcomp.cache/misaligned.exp | 56 ++ sid/component/testsuite/sidcomp.cache/prefetch.exp | 44 ++ sid/component/testsuite/sidcomp.cache/random.exp | 47 ++ sid/component/testsuite/sidcomp.cache/types.exp | 44 ++ sid/component/testsuite/sidcomp.cache/utils.exp | 47 ++ .../testsuite/sidcomp.cache/writealloc.exp | 85 +++ .../testsuite/sidcomp.cache/writethru.exp | 93 +++ 30 files changed, 3109 insertions(+), 6 deletions(-) create mode 100644 sid/component/cache/ChangeLog create mode 100644 sid/component/cache/Makefile.am create mode 100644 sid/component/cache/Makefile.in create mode 100644 sid/component/cache/cache.cxx create mode 100644 sid/component/cache/cache.h create mode 100644 sid/component/cache/cacheutil.cxx create mode 100644 sid/component/cache/cacheutil.h create mode 100644 sid/component/cache/hw-cache.txt create mode 100644 sid/component/cache/log2.h create mode 100644 sid/component/testsuite/sidcomp.cache/cache.exp create mode 100644 sid/component/testsuite/sidcomp.cache/cachedocs.exp create mode 100644 sid/component/testsuite/sidcomp.cache/cachemonkey.exp create mode 100644 sid/component/testsuite/sidcomp.cache/coherency.exp create mode 100644 sid/component/testsuite/sidcomp.cache/fifo.exp create mode 100644 sid/component/testsuite/sidcomp.cache/flush.exp create mode 100644 sid/component/testsuite/sidcomp.cache/lock.exp create mode 100644 sid/component/testsuite/sidcomp.cache/lru.exp create mode 100644 sid/component/testsuite/sidcomp.cache/misaligned.exp create mode 100644 sid/component/testsuite/sidcomp.cache/prefetch.exp create mode 100644 sid/component/testsuite/sidcomp.cache/random.exp create mode 100644 sid/component/testsuite/sidcomp.cache/types.exp create mode 100644 sid/component/testsuite/sidcomp.cache/utils.exp create mode 100644 sid/component/testsuite/sidcomp.cache/writealloc.exp create mode 100644 sid/component/testsuite/sidcomp.cache/writethru.exp diff --git a/sid/component/CATALOG b/sid/component/CATALOG index 336b3219f6..41ac63d2d7 100644 --- a/sid/component/CATALOG +++ b/sid/component/CATALOG @@ -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) diff --git a/sid/component/ChangeLog b/sid/component/ChangeLog index a465ba359b..01ec980789 100644 --- a/sid/component/ChangeLog +++ b/sid/component/ChangeLog @@ -1,3 +1,10 @@ +2001-06-12 Ben Elliston + + * CATALOG: Add hw-cache-basic and friends. + * configure.in (make_subdirs): Add cache. + * configure: Regenerate. + * Makefile.in: Ditto. + 2001-03-26 Frank Ch. Eigler * CATALOG: Add hw-visual-probe-bus, hw-visual-probe-pin. diff --git a/sid/component/Makefile.in b/sid/component/Makefile.in index 81c5cfa09a..4e5ffed818 100644 --- a/sid/component/Makefile.in +++ b/sid/component/Makefile.in @@ -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 index 0000000000..ee74387cd5 --- /dev/null +++ b/sid/component/cache/ChangeLog @@ -0,0 +1,13 @@ +2001-06-15 Ben Elliston + + * 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 + + * 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 index 0000000000..698876da8e --- /dev/null +++ b/sid/component/cache/Makefile.am @@ -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 index 0000000000..69d08ea2f2 --- /dev/null +++ b/sid/component/cache/Makefile.in @@ -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 index 0000000000..ffb95beda0 --- /dev/null +++ b/sid/component/cache/cache.cxx @@ -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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 +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 +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 (stats.read_hits) / stats.reads) * 100; + return make_attribute (static_cast (rate)) + "%"; + } +} + +string +cache_component::write_hit_rate () +{ + if (stats.writes == 0) + return "0%"; + else + { + float rate = (static_cast (stats.write_hits) / stats.writes) * 100; + return make_attribute (static_cast (rate)) + "%"; + } +} + +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 candidates(fifo); + + int n = fifo.size (); + while (n > 0) + { + vector::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 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--; + } + } +} + + +extern const sid::component_library cache_component_library; + +static vector +CacheListTypes () +{ + string type; + vector 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 "kb", where 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(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 index 0000000000..525306e09f --- /dev/null +++ b/sid/component/cache/cache.h @@ -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 + bus::status write_any (host_int_4 addr, DataType data) + { + return cache.write_any (addr, data); + } + + template + 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 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 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); +}; + + +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 bus::status + write_any (host_int_4 addr, DataType data); + + template bus::status + read_any (host_int_4 addr, DataType& data); + +private: + cache acache; + + cache_bus upstream; + bus* downstream; + + callback_pin report_pin; + void emit_report (host_int_4 ignore); + + callback_pin flush_pin; + void flush_line (host_int_4 addr); + + callback_pin invalidate_all_pin; + void invalidate_all_lines (host_int_4 ignore); + + callback_pin invalidate_pin; + void invalidate_line (host_int_4 addr); + + callback_pin prefetch_pin; + void prefetch_line (host_int_4 addr); + + callback_pin lock_pin; + void lock_line (host_int_4 addr); + + callback_pin 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 index 0000000000..f944fade2f --- /dev/null +++ b/sid/component/cache/cacheutil.cxx @@ -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 (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 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 index 0000000000..7f549c1421 --- /dev/null +++ b/sid/component/cache/cacheutil.h @@ -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 +#include + +#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 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 + 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 + 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 lines; + typedef vector ::iterator iterator_t; + typedef vector ::const_iterator const_iterator_t; +}; + + +// 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 sets; + typedef vector ::iterator iterator_t; + typedef vector ::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 index 0000000000..bd7b2b6117 --- /dev/null +++ b/sid/component/cache/hw-cache.txt @@ -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 index 0000000000..74c7a994df --- /dev/null +++ b/sid/component/cache/log2.h @@ -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 +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 +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 diff --git a/sid/component/configure b/sid/component/configure index 07d5d00b38..367b905fb8 100755 --- a/sid/component/configure +++ b/sid/component/configure @@ -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 < + + * 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 * 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 index 0000000000..22b5b9c482 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/cache.exp @@ -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 index 0000000000..8eb29a166b --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/cachedocs.exp @@ -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 index 0000000000..32e72a6e9f --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/cachemonkey.exp @@ -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 index 0000000000..4118291cfa --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/coherency.exp @@ -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 index 0000000000..28880ed616 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/fifo.exp @@ -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 index 0000000000..018e75eea2 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/flush.exp @@ -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 index 0000000000..28b06a8c9a --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/lock.exp @@ -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 index 0000000000..ae4abbe17f --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/lru.exp @@ -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 index 0000000000..270ab47266 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/misaligned.exp @@ -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 index 0000000000..bc99b78be6 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/prefetch.exp @@ -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 index 0000000000..9ec5ea50f6 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/random.exp @@ -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 index 0000000000..dbaec798d6 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/types.exp @@ -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 index 0000000000..a7735511d0 --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/utils.exp @@ -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 index 0000000000..bc85c5fd3b --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/writealloc.exp @@ -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 index 0000000000..f7b82a316f --- /dev/null +++ b/sid/component/testsuite/sidcomp.cache/writethru.exp @@ -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 -- 2.11.0