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
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)
+2001-06-12 Ben Elliston <bje@redhat.com>
+
+ * CATALOG: Add hw-cache-basic and friends.
+ * configure.in (make_subdirs): Add cache.
+ * configure: Regenerate.
+ * Makefile.in: Ditto.
+
2001-03-26 Frank Ch. Eigler <fche@redhat.com>
* CATALOG: Add hw-visual-probe-bus, hw-visual-probe-pin.
&& 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)
--- /dev/null
+2001-06-15 Ben Elliston <bje@redhat.com>
+
+ * cache.cxx: New file.
+ * cache.h: Likewise.
+ * cacheutil.cxx: Likewise.
+ * cacheutil.h: Likewise.
+ * log2.h: Likewise.
+ * hw-cache.txt: Likewise.
+
+2001-06-05 Ben Elliston <bje@redhat.com>
+
+ * Makefile.am: New file.
+ * Makefile.in: Generate.
--- /dev/null
+## 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)")
--- /dev/null
+# 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:
--- /dev/null
+// cache.cxx -- A universal memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "config.h"
+
+#include <sidcomp.h>
+#include <sidso.h>
+#include <sidcomputil.h>
+#include <sidattrutil.h>
+#include <sidpinutil.h>
+#include <sidbusutil.h>
+#include <sidtypes.h>
+
+#include <algorithm>
+#include <stdlib.h>
+#include <vector>
+#include <string>
+#include <iostream>
+
+#include "cache.h"
+
+string line_sizes[] =
+ { "16", "32", "64", "128" };
+
+string cache_sizes[] =
+ { "8", "16", "32", "64", "128", "256", "512" };
+
+string assocs[] =
+ { "direct", "full", "2way", "4way" };
+
+string replacement_algorithms[] =
+ { "lru", "fifo", "random" };
+
+// One per replacement policy
+static cache_replacement_null null_replacement;
+static cache_replacement_lru lru_replacement;
+static cache_replacement_fifo fifo_replacement;
+static cache_replacement_random random_replacement;
+
+cache_component::cache_component (unsigned assocy,
+ unsigned cache_sz,
+ unsigned line_sz,
+ cache_replacement_algorithm& replacer)
+ :report_pin (this, &cache_component::emit_report),
+ flush_pin (this, &cache_component::flush_line),
+ invalidate_all_pin (this, &cache_component::invalidate_all_lines),
+ invalidate_pin (this, &cache_component::invalidate_line),
+ prefetch_pin (this, &cache_component::prefetch_line),
+ lock_pin (this, &cache_component::lock_line),
+ unlock_pin (this, &cache_component::unlock_line),
+ write_allocate_p (false),
+ write_through_p (false),
+ downstream (0),
+ upstream (*this),
+ collect_p (true),
+ line_size (line_sz),
+ cache_size (cache_sz),
+ assoc (assocy),
+ report_heading ("cache profile report"),
+ acache (cache_sz, line_sz, assocy, replacer)
+{
+ memset (&stats, 0, sizeof (stats));
+
+ add_bus ("upstream", &upstream);
+ add_accessor ("downstream", &downstream);
+
+ add_pin ("report!", &report_pin);
+ add_pin ("flush", &flush_pin);
+ add_pin ("invalidate-all", &invalidate_all_pin);
+ add_pin ("invalidate", &invalidate_pin);
+ add_pin ("prefetch", &prefetch_pin);
+ add_pin ("lock", &lock_pin);
+ add_pin ("unlock", &unlock_pin);
+
+ add_attribute_ro ("cache-size", &cache_size, "setting");
+ add_attribute_ro ("line-size", &line_size, "setting");
+ add_attribute_virtual ("associativity", this,
+ &cache_component::associativity,
+ &cache_component::set_nothing,
+ "setting");
+
+ add_attribute ("write-through?", &write_through_p, "setting");
+ add_attribute ("write-allocate?", &write_allocate_p, "setting");
+
+ add_attribute_virtual ("hash-bit-mask", this,
+ &cache_component::get_hash_mask,
+ &cache_component::set_hash_mask,
+ "setting");
+
+ add_attribute_virtual ("hash-shift-amount", this,
+ &cache_component::get_hash_shift,
+ &cache_component::set_hash_shift,
+ "setting");
+
+ add_attribute ("collect-statistics?", &collect_p, "setting");
+ add_attribute ("report-heading", &report_heading, "setting");
+
+ add_attribute_virtual ("dump!", this,
+ &cache_component::get_nothing,
+ &cache_component::dump,
+ "setting");
+
+ add_attribute_ro ("read-accesses", &stats.reads, "register");
+ add_attribute_ro ("write-accesses", &stats.writes, "register");
+ add_attribute_ro ("misaligned-reads", &stats.misaligned_reads, "register");
+ add_attribute_ro ("misaligned-writes", &stats.misaligned_writes, "register");
+ add_attribute_ro ("flushes", &stats.flushes, "register");
+ add_attribute_ro ("replacements", &stats.replacements, "register");
+
+ add_attribute_virtual ("read-hit-rate", this,
+ &cache_component::read_hit_rate,
+ &cache_component::set_nothing,
+ "register");
+
+ add_attribute_virtual ("write-hit-rate", this,
+ &cache_component::write_hit_rate,
+ &cache_component::set_nothing,
+ "register");
+
+ // FIXME: state save/restore
+}
+
+unsigned
+cache_component::line_offset (const cache_line& line, const host_int_4& addr)
+{
+ return addr - acache.tag_to_addr (line.tag ());
+}
+
+template <typename DataType>
+bus::status
+cache_component::write_any (host_int_4 addr, DataType data)
+{
+ bool hit;
+ bus::status st;
+
+ if (UNLIKELY (downstream == 0))
+ return bus::unmapped;
+
+ if (LIKELY (collect_p))
+ stats.writes++;
+
+ if (UNLIKELY (addr % sizeof (data) != 0))
+ {
+ // Punt on misaligned accesses
+ if (LIKELY (collect_p))
+ stats.misaligned_writes++;
+
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (hit)
+ {
+ if (line.dirty_p ())
+ {
+ // flush a dirty line being replaced
+ if ((st = write_line (line)) != bus::ok)
+ return st;
+ }
+ acache.expunge (line);
+ }
+ return downstream->read (addr, data);
+ }
+
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (LIKELY (hit))
+ {
+ if (LIKELY (collect_p))
+ stats.write_hits++;
+ line.insert (line_offset (line, addr), data);
+ if (write_through_p)
+ {
+ if ((st = downstream->write (addr, data)) != bus::ok)
+ return st;
+ }
+ }
+ else
+ {
+ if (write_allocate_p)
+ {
+ if (acache.vacancy_p (addr))
+ {
+ cache_line expelled_line (line_size);
+ cache_line new_line (line_size, acache.addr_to_tag (addr));
+ if ((st = read_line (new_line)) != bus::ok)
+ return st;
+
+ new_line.insert (line_offset (new_line, addr), data);
+ acache.replace (expelled_line, new_line);
+
+ if (collect_p)
+ stats.replacements++;
+
+ if (expelled_line.dirty_p () && !write_through_p)
+ {
+ // flush a dirty line being replaced
+ if ((st = write_line (expelled_line)) != bus::ok)
+ return st;
+ }
+
+ if (write_through_p)
+ {
+ if ((st = downstream->write (addr, data)) != bus::ok)
+ return st;
+ }
+ }
+ }
+ else
+ {
+ // write through to memory to preserve the write
+ if ((st = downstream->write (addr, data)) != bus::ok)
+ return st;
+ }
+ }
+ return bus::ok;
+}
+
+template <typename DataType>
+bus::status
+cache_component::read_any (host_int_4 addr, DataType& data)
+{
+ if (UNLIKELY (downstream == 0))
+ return bus::unmapped;
+
+ if (LIKELY (collect_p))
+ stats.reads++;
+
+ // Punt on misaligned accesses
+ if (UNLIKELY (addr % sizeof (data) != 0))
+ {
+ if (LIKELY (collect_p))
+ stats.misaligned_reads++;
+ return downstream->read (addr, data);
+ }
+
+ bool hit;
+ bus::status st;
+
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (LIKELY (hit))
+ {
+ if (LIKELY (collect_p))
+ stats.read_hits++;
+ line.extract (line_offset (line, addr), data);
+ }
+ else
+ {
+ // miss!
+ if (acache.vacancy_p (addr))
+ {
+ cache_line expelled_line (line_size);
+ cache_line new_line (line_size, acache.addr_to_tag (addr));
+
+ if ((st = read_line (new_line)) != bus::ok)
+ return st;
+ new_line.extract (line_offset (new_line, addr), data);
+
+ acache.replace (expelled_line, new_line);
+
+ if (collect_p)
+ stats.replacements++;
+
+ if (expelled_line.dirty_p ())
+ {
+ // flush a dirty line being replaced
+ if ((st = write_line (expelled_line)) != bus::ok)
+ return st;
+ }
+ }
+ else
+ return downstream->read (addr, data);
+ }
+ return bus::ok;
+}
+
+bus::status
+cache_component::read_line (cache_line& line)
+{
+ host_int_4 base = acache.tag_to_addr (line.tag ());
+ for (host_int_4 offset = 0; offset < line_size; offset += 4)
+ {
+ sid::big_int_4 data;
+ bus::status st = downstream->read (base + offset, data);
+ if (st != bus::ok)
+ return st;
+ line.insert (offset, data);
+ }
+ line.unlock ();
+ line.clean ();
+ line.validate ();
+ return bus::ok;
+}
+
+bus::status
+cache_component::write_line (cache_line& line)
+{
+ host_int_4 base = acache.tag_to_addr (line.tag ());
+ for (host_int_4 offset = 0; offset < line_size; offset += 4)
+ {
+ sid::big_int_4 data;
+ line.extract (offset, data);
+ bus::status st = downstream->write (base + offset, data);
+ if (st != bus::ok)
+ return st;
+ }
+ line.clean ();
+ if (LIKELY (collect_p))
+ stats.flushes++;
+ return bus::ok;
+}
+
+void
+cache_component::flush_line (host_int_4 addr)
+{
+ bool hit;
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (hit && line.dirty_p ())
+ bus::status st = write_line (line);
+}
+
+void
+cache_component::invalidate_all_lines (host_int_4 ignore)
+{
+ acache.invalidate ();
+}
+
+void
+cache_component::invalidate_line (host_int_4 addr)
+{
+ bool hit;
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (hit)
+ line.invalidate ();
+}
+
+void
+cache_component::prefetch_line (host_int_4 addr)
+{
+ sid::big_int_1 dummy;
+ bus::status st = read_any (addr, dummy);
+}
+
+void
+cache_component::lock_line (host_int_4 addr)
+{
+ bool hit;
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (hit)
+ line.lock ();
+}
+
+void
+cache_component::unlock_line (host_int_4 addr)
+{
+ bool hit;
+ cache_line& line = acache.find (acache.addr_to_tag (addr), hit);
+ if (hit)
+ line.unlock ();
+}
+
+void
+cache_component::emit_report (host_int_4 ignore)
+{
+ cout << report_heading << endl << endl
+ << "reads: " << make_attribute (stats.reads) << endl
+ << "read hits: " << read_hit_rate () << endl
+ << "writes: " << make_attribute (stats.writes) << endl
+ << "write hits: " << write_hit_rate () << endl
+ << "replacements: " << make_attribute (stats.replacements) << endl
+ << "flushes: " << make_attribute (stats.flushes) << endl;
+}
+
+string
+cache_component::get_hash_mask ()
+{
+ return make_attribute (acache.hash_params.mask);
+}
+
+string
+cache_component::get_hash_shift ()
+{
+ return make_attribute (acache.hash_params.shift);
+}
+
+sid::component::status
+cache_component::set_hash_mask (const string& value)
+{
+ unsigned shift;
+ parse_attribute (value, shift);
+
+ if ((acache.hash_params.mask >> shift) >= acache.num_sets ())
+ return sid::component::bad_value;
+
+ acache.hash_params.shift = shift;
+ return sid::component::ok;
+}
+
+sid::component::status
+cache_component::set_hash_shift (const string& value)
+{
+ sid::host_int_4 mask;
+ parse_attribute (value, mask);
+
+ if ((mask >> acache.hash_params.shift) >= acache.num_sets ())
+ return sid::component::bad_value;
+
+ acache.hash_params.mask = mask;
+ return sid::component::ok;
+}
+
+sid::component::status
+cache_component::dump (const string& ignore)
+{
+ acache.dump ();
+ return sid::component::ok;
+}
+
+string
+cache_component::associativity ()
+{
+ switch (assoc)
+ {
+ case 0:
+ return "fully-associative";
+ case 1:
+ return "direct-mapped";
+ default:
+ return make_attribute (assoc) + "-way";
+ }
+}
+
+string
+cache_component::read_hit_rate ()
+{
+ if (stats.reads == 0)
+ return "0%";
+ else
+ {
+ float rate = (static_cast<float> (stats.read_hits) / stats.reads) * 100;
+ return make_attribute (static_cast<int> (rate)) + "%";
+ }
+}
+
+string
+cache_component::write_hit_rate ()
+{
+ if (stats.writes == 0)
+ return "0%";
+ else
+ {
+ float rate = (static_cast<float> (stats.write_hits) / stats.writes) * 100;
+ return make_attribute (static_cast<int> (rate)) + "%";
+ }
+}
+\f
+void
+cache_replacement_fifo::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+ // If this is the first time through, expand fifo accordingly.
+ if (fifo.size () != cset.num_lines ())
+ fifo.resize (cset.num_lines ());
+
+ for (unsigned i = 0; i < fifo.size (); i++)
+ fifo[i]++;
+
+ unsigned i;
+ vector<int> candidates(fifo);
+
+ int n = fifo.size ();
+ while (n > 0)
+ {
+ vector<int>::iterator it;
+ it = max_element (candidates.begin (), candidates.end ());
+ i = distance (candidates.begin (), it);
+ cache_line& line = cset.get_line (i);
+ if (line.locked_p ())
+ {
+ *it = -1;
+ }
+ else
+ {
+ old_line = line;
+ old_line.invalidate ();
+ cset.set_line (i, new_line);
+
+ // update state
+ fifo[i] = 0;
+ return;
+ }
+ n--;
+ }
+}
+
+void
+cache_replacement_lru::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+ int oldest;
+ int index = -1;
+ lru.resize (cset.num_lines ());
+
+ for (unsigned i = 0, oldest = 0; i < cset.num_lines (); i++)
+ {
+ cache_line& line = cset.get_line (i);
+ if (!line.valid_p ())
+ {
+ index = i;
+ break;
+ }
+ else if (!line.locked_p () && lru[i] > oldest)
+ {
+ index = i;
+ oldest = lru[i];
+ }
+ }
+
+ if (index < 0)
+ return;
+
+ old_line = cset.get_line (index);
+ old_line.invalidate ();
+ cset.set_line (index, new_line);
+ lru[index] = 0;
+}
+
+void
+cache_replacement_lru::update (cache_set& cset, cache_line& selected_line)
+{
+ cache_tag t = selected_line.tag ();
+ for (unsigned i = 0; i < lru.size (); i++)
+ {
+ if (cset.get_line (i) == t)
+ lru[i] = 0;
+ else
+ lru[i]++;
+ }
+}
+
+void
+cache_replacement_null::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+ cache_line& line = cset.get_line (0);
+ if (!line.locked_p ())
+ {
+ old_line = line;
+ old_line.invalidate ();
+ cset.set_line (0, new_line);
+ }
+}
+
+void
+cache_replacement_random::replace (cache_set& cset, cache_line& old_line, cache_line new_line)
+{
+ for (unsigned i = 0; i < cset.num_lines (); i++)
+ {
+ cache_line& line = cset.get_line (i);
+ if (!line.valid_p ())
+ {
+ old_line = line;
+ old_line.invalidate ();
+ cset.set_line (i, new_line);
+ return;
+ }
+ }
+
+ unsigned n = cset.num_lines ();
+ vector<bool> candidates(n, true);
+
+ while (n > 0)
+ {
+ unsigned i = rand () % cset.num_lines ();
+
+ // Try, try again.
+ if (!candidates[i]) continue;
+
+ cache_line& line = cset.get_line (i);
+ if (!line.locked_p ())
+ {
+ old_line = line;
+ old_line.invalidate ();
+ cset.set_line (i, new_line);
+ return;
+ }
+ else
+ {
+ candidates[i] = false;
+ n--;
+ }
+ }
+}
+
+\f
+extern const sid::component_library cache_component_library;
+
+static vector<string>
+CacheListTypes ()
+{
+ string type;
+ vector<string> types;
+
+ types.push_back ("hw-cache-basic");
+
+ for (int i = 0; i < (sizeof (assocs) / sizeof (string)); i++)
+ for (int j = 0; j < (sizeof (cache_sizes) / sizeof (string)); j++)
+ for (int k = 0; k < (sizeof (line_sizes) / sizeof (string)); k++)
+ {
+ if (assocs[i] == "direct")
+ {
+ type = string ("hw-cache-direct/");
+ type += cache_sizes[j] + "kb/";
+ type += line_sizes[k];
+ types.push_back (type);
+ }
+ else
+ for (int m = 0;
+ m < (sizeof (replacement_algorithms) / sizeof (string)); m++)
+ {
+ type = string ("hw-cache-");
+ type += assocs[i] + "/";
+ type += cache_sizes[j] + "kb/";
+ type += line_sizes[k] + "/";
+ type += replacement_algorithms[m];
+ types.push_back (type);
+ }
+ }
+ return types;
+}
+
+static component*
+CacheCreate (const string& typeName)
+{
+ bool match;
+ int i, index = 0, pos;
+ int assoc, linesz, cachesz;
+
+ if (typeName == "hw-cache-basic")
+ return new cache_component (1, 16384, 32, null_replacement);
+
+ if (typeName.find ("hw-cache-", index) != 0)
+ return 0;
+ index += strlen ("hw-cache-");
+
+ // parse assoc + "/"
+ if ((pos = typeName.find_first_of ("/", index)) == string::npos)
+ return 0;
+ string assoc_string = typeName.substr (index, (pos - index));
+ index = pos + 1;
+
+ string cache_size_string;
+
+ // Parse "<x>kb", where <x> is a positive integer.
+ if ((pos = typeName.find_first_of ("/", index)) == string::npos)
+ return 0;
+ cache_size_string = typeName.substr (index, (pos - index));
+ index = pos + 1;
+
+ if ((pos = cache_size_string.find ("kb", 0)) == string::npos)
+ return 0;
+ cache_size_string.erase (pos, cache_size_string.length () - pos);
+
+ string line_size_string;
+ string replace_alg_string;
+
+ if (assoc_string == "direct")
+ line_size_string = typeName.substr (index, (typeName.length () - index));
+ else
+ {
+ if ((pos = typeName.find_first_of ("/", index)) == string::npos)
+ return 0;
+ line_size_string = typeName.substr (index, (pos - index));
+ index = pos + 1;
+ replace_alg_string = typeName.substr (index, (typeName.length () - index));
+ }
+
+ for (match = false, i = 0; i < sizeof (assocs) / sizeof (string); i++)
+ if (assoc_string == assocs[i])
+ match = true;
+ if (!match)
+ return 0;
+
+ for (match = false, i = 0; i < sizeof (cache_sizes) / sizeof (string); i++)
+ if (cache_size_string == cache_sizes[i])
+ {
+ cachesz = atoi (cache_size_string.c_str ()) * 1024;
+ match = true;
+ }
+ if (!match)
+ return 0;
+
+ for (match = false, i = 0; i < sizeof (line_sizes) / sizeof (string); i++)
+ if (line_size_string == line_sizes[i])
+ {
+ linesz = atoi (line_size_string.c_str ());
+ match = true;
+ }
+ if (!match)
+ return 0;
+
+ if (assoc_string != "direct")
+ {
+ for (match = false, i = 0;
+ i < sizeof (replacement_algorithms) / sizeof (string); i++)
+ {
+ if (replace_alg_string == replacement_algorithms[i])
+ match = true;
+ }
+ if (!match)
+ return 0;
+ }
+
+ if (assoc_string == "full")
+ assoc = 0;
+ else if (assoc_string == "direct")
+ assoc = 1;
+ else
+ {
+ if ((pos = assoc_string.find ("way", 0)) == string::npos)
+ return 0;
+ assoc_string.erase (pos, assoc_string.length () - pos);
+ if ((assoc = atoi (assoc_string.c_str ())) == 0)
+ return 0;
+ }
+
+ if (assoc == 1)
+ return new cache_component (assoc, cachesz, linesz, null_replacement);
+
+ if (replace_alg_string == "lru")
+ return new cache_component (assoc, cachesz, linesz, lru_replacement);
+ else if (replace_alg_string == "fifo")
+ return new cache_component (assoc, cachesz, linesz, fifo_replacement);
+ else if (replace_alg_string == "random")
+ return new cache_component (assoc, cachesz, linesz, random_replacement);
+
+ return 0;
+}
+
+static void
+CacheDelete (component* c)
+{
+ delete dynamic_cast<cache_component*>(c);
+}
+
+const sid::component_library cache_component_library DLLEXPORT =
+{
+ sid::COMPONENT_LIBRARY_MAGIC,
+ &CacheListTypes,
+ &CacheCreate,
+ &CacheDelete
+};
--- /dev/null
+// cache.h -- A universal memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef CACHE_H
+#define CACHE_H
+
+#include "cacheutil.h"
+
+using std::string;
+using std::vector;
+
+using sid::bus;
+using sid::component;
+using sid::host_int_4;
+
+using sidutil::fixed_attribute_map_component;
+using sidutil::fixed_bus_map_component;
+using sidutil::fixed_pin_map_component;
+using sidutil::fixed_accessor_map_component;
+using sidutil::no_relation_component;
+using sidutil::callback_pin;
+using sidutil::make_attribute;
+using sidutil::parse_attribute;
+
+class cache_component;
+class cache_bus: public bus
+{
+public:
+ cache_bus (cache_component& c)
+ :cache(c) {}
+
+private:
+ cache_component& cache;
+
+ template <typename DataType>
+ bus::status write_any (host_int_4 addr, DataType data)
+ {
+ return cache.write_any (addr, data);
+ }
+
+ template <typename DataType>
+ bus::status read_any (host_int_4 addr, DataType& data)
+ {
+ return cache.read_any (addr, data);
+ }
+
+#define DEFN_METHOD(DataType) \
+ bus::status write(host_int_4 addr, DataType data) throw () { return this->write_any(addr, data); } \
+ bus::status read(host_int_4 addr, DataType& data) throw () { return this->read_any(addr, data); }
+
+ DEFN_METHOD (sid::big_int_1)
+ DEFN_METHOD (sid::big_int_2)
+ DEFN_METHOD (sid::big_int_4)
+ DEFN_METHOD (sid::big_int_8)
+ DEFN_METHOD (sid::little_int_1)
+ DEFN_METHOD (sid::little_int_2)
+ DEFN_METHOD (sid::little_int_4)
+ DEFN_METHOD (sid::little_int_8)
+};
+
+// FIFO cache replacement algorithm
+
+class cache_replacement_fifo: public cache_replacement_algorithm
+{
+public:
+ void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+
+private:
+ vector <int> fifo;
+};
+
+// Least recently used (LRU) replacement algorithm
+
+class cache_replacement_lru: public cache_replacement_algorithm
+{
+public:
+ void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+ void update (cache_set& cset, cache_line& selected);
+
+private:
+ vector <int> lru;
+};
+
+// Random replacement algorithm
+
+class cache_replacement_random: public cache_replacement_algorithm
+{
+public:
+ void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+};
+
+// Null replacement algorithm; used by direct mapped caches
+
+class cache_replacement_null: public cache_replacement_algorithm
+{
+public:
+ void replace (cache_set& cset, cache_line& old_line, cache_line new_line);
+};
+
+\f
+class cache_component: public virtual component,
+ protected fixed_attribute_map_component,
+ protected fixed_bus_map_component,
+ protected fixed_pin_map_component,
+ protected fixed_accessor_map_component,
+ protected no_relation_component
+{
+public:
+ cache_component (unsigned asoctvty, unsigned cache_sz,
+ unsigned line_sz, cache_replacement_algorithm& replacer);
+
+ template <typename DataType> bus::status
+ write_any (host_int_4 addr, DataType data);
+
+ template <typename DataType> bus::status
+ read_any (host_int_4 addr, DataType& data);
+
+private:
+ cache acache;
+
+ cache_bus upstream;
+ bus* downstream;
+
+ callback_pin<cache_component> report_pin;
+ void emit_report (host_int_4 ignore);
+
+ callback_pin<cache_component> flush_pin;
+ void flush_line (host_int_4 addr);
+
+ callback_pin<cache_component> invalidate_all_pin;
+ void invalidate_all_lines (host_int_4 ignore);
+
+ callback_pin<cache_component> invalidate_pin;
+ void invalidate_line (host_int_4 addr);
+
+ callback_pin<cache_component> prefetch_pin;
+ void prefetch_line (host_int_4 addr);
+
+ callback_pin<cache_component> lock_pin;
+ void lock_line (host_int_4 addr);
+
+ callback_pin<cache_component> unlock_pin;
+ void unlock_line (host_int_4 addr);
+
+ string read_hit_rate ();
+ string write_hit_rate ();
+ string get_nothing () { return ""; }
+ status set_nothing (const string& ignore) { return sid::component::ok; }
+ string associativity ();
+ status dump (const string& ignore);
+ string get_hash_mask ();
+ status set_hash_mask (const string& ignore);
+ string get_hash_shift ();
+ status set_hash_shift (const string& ignore);
+
+ unsigned line_offset (const cache_line& line, const host_int_4& addr);
+
+ bus::status read_line (cache_line& line);
+ bus::status write_line (cache_line& line);
+
+ bool write_allocate_p;
+ bool write_through_p;
+ bool collect_p;
+ string report_heading;
+
+ struct
+ {
+ unsigned long reads;
+ unsigned long writes;
+ unsigned long read_hits;
+ unsigned long write_hits;
+ unsigned long misaligned_reads;
+ unsigned long misaligned_writes;
+ unsigned long flushes;
+ unsigned long replacements;
+ } stats;
+
+ unsigned line_size;
+ unsigned cache_size;
+ unsigned assoc;
+};
+
+#endif // CACHE_H
--- /dev/null
+// cacheutil.cxx -- Helper classes for a generic memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#include "cacheutil.h"
+
+bool
+std::operator== (const cache_tag& tag, const cache_line& line)
+{
+ return (line.valid_p () && tag == line.tag ());
+}
+
+bool
+std::operator== (const cache_line& line, const cache_tag& tag)
+{
+ return (line.valid_p () && tag == line.tag ());
+}
+
+cache_line::cache_line (const cache_line& other)
+{
+ size = other.size;
+ valid_bit = other.valid_bit;
+ dirty_bit = other.dirty_bit;
+ lock_bit = other.lock_bit;
+ atag = other.atag;
+ data = new byte [size];
+ memcpy (data, other.data, size);
+}
+
+cache_line&
+cache_line::operator= (const cache_line& other)
+{
+ if (this != &other)
+ {
+ // Beware of self-assignment.
+ size = other.size;
+ valid_bit = other.valid_bit;
+ dirty_bit = other.dirty_bit;
+ lock_bit = other.lock_bit;
+ atag = other.atag;
+ delete [] data;
+ data = new byte [size];
+ memcpy (data, other.data, size);
+ }
+ return *this;
+}
+
+void
+cache_line::dump () const
+{
+ cerr << " ";
+
+ if (dirty_p ()) cerr << 'M'; else cerr << '-';
+ if (valid_p ()) cerr << 'V'; else cerr << '-';
+ if (locked_p ()) cerr << 'L'; else cerr << '-';
+
+ cerr << " " << hex << setw (4) << setfill ('0') << atag << "\t";
+ for (unsigned i = 0; i < size; i++)
+ cerr << setw (2) << setfill ('0') << static_cast<unsigned> (data[i]);
+
+ cerr << dec << endl;
+}
+
+cache_line::cache_line (unsigned line_size)
+ :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (0)
+{
+ data = new byte[line_size];
+ memset (data, 0, line_size);
+}
+
+cache_line::cache_line (unsigned line_size, cache_tag t)
+ :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (t)
+{
+ data = new byte[line_size];
+ memset (data, 0, line_size);
+}
+
+cache_line::cache_line (unsigned line_size, cache_tag t, vector<byte> initial_data)
+ :size (line_size), valid_bit (false), dirty_bit (false), lock_bit (false), atag (t)
+{
+ assert (initial_data.size () == line_size);
+ data = new byte[line_size];
+ for (unsigned i = 0; i < line_size; i++)
+ data[i] = initial_data[i];
+}
+
+cache_line::~cache_line ()
+{
+ delete [] data;
+}
+
+void
+cache_line::dirty ()
+{
+ dirty_bit = true;
+}
+
+void
+cache_line::clean ()
+{
+ dirty_bit = false;
+}
+
+void
+cache_line::validate ()
+{
+ valid_bit = true;
+}
+
+void
+cache_line::invalidate ()
+{
+ valid_bit = false;
+}
+
+void
+cache_line::lock ()
+{
+ lock_bit = true;
+}
+
+void
+cache_line::unlock ()
+{
+ lock_bit = false;
+}
+
+cache_tag
+cache_line::tag () const
+{
+ return atag;
+}
+
+bool
+cache_line::dirty_p () const
+{
+ return dirty_bit;
+}
+
+bool
+cache_line::valid_p () const
+{
+ return valid_bit;
+}
+
+bool
+cache_line::locked_p () const
+{
+ return lock_bit;
+}
+
+cache_set::cache_set (unsigned line_size, unsigned nlines, cache_replacement_algorithm& alg)
+ :replacer (alg)
+{
+ lines.resize (nlines);
+ for (iterator_t it = lines.begin(); it != lines.end (); it++)
+ *it = new cache_line (line_size);
+}
+
+cache_set::~cache_set ()
+{
+ for (iterator_t it = lines.begin (); it != lines.end (); it++)
+ delete *it;
+}
+
+unsigned
+cache_set::num_lines () const
+{
+ return lines.size ();
+}
+
+cache_line&
+cache_set::get_line (unsigned i) const
+{
+ return *lines[i];
+}
+
+void
+cache_set::set_line (unsigned i, const cache_line line)
+{
+ *lines[i] = line;
+}
+
+cache_line&
+cache_set::find (const cache_tag& tag, bool& hit)
+{
+ static cache_line dummy(0);
+
+ // Scan the lines in this set for tag. Might as well be linear; the
+ // order of associativity will be small.
+
+ for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
+ if (tag == *(*it))
+ {
+ hit = true;
+ replacer.update (*this, *(*it));
+ return *(*it);
+ }
+ hit = false;
+ return dummy;
+}
+
+void
+cache_set::invalidate ()
+{
+ for (iterator_t it = lines.begin (); it != lines.end (); it++)
+ (*it)->invalidate ();
+}
+
+bool
+cache_set::vacancy_p () const
+{
+ for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
+ if (!(*it)->locked_p ())
+ return true;
+
+ return false;
+}
+
+void
+cache_set::expunge_line (cache_line& line)
+{
+ line.unlock ();
+ line.clean ();
+ line.invalidate ();
+}
+
+void
+cache_set::replace_line (cache_line& old_line, cache_line new_line)
+{
+ return replacer.replace (*this, old_line, new_line);
+}
+
+void
+cache_set::dump () const
+{
+ for (const_iterator_t it = lines.begin (); it != lines.end (); it++)
+ (*it)->dump ();
+}
+
+cache::cache (unsigned cache_size, unsigned line_size, unsigned assoc,
+ cache_replacement_algorithm& replacer)
+{
+ assert (power_of_two_p (line_size));
+ assert (cache_size >= line_size);
+
+ // The cache size must be an even multiple of the line size.
+ assert ((cache_size % line_size) == 0);
+
+ int num_lines = cache_size / line_size;
+ if (assoc > 0)
+ assert (num_lines % assoc == 0 && assoc < num_lines);
+
+ // The number of sets.
+ // If the cache is fully associative, there is only one set.
+ int num_sets = (assoc == 0) ? 1 : (num_lines / assoc);
+ sets.resize (num_sets);
+
+ // The number of lines per set.
+ // If the cache is fully associative, there is one set with as many
+ // lines as there are in the cache.
+ int lines_per_set = (assoc == 0) ? num_lines : assoc;
+
+ for (iterator_t it = sets.begin (); it != sets.end (); it++)
+ *it = new cache_set (line_size, lines_per_set, replacer);
+
+ num_non_tag_bits = log2 (line_size);
+
+ // suitable defaults
+ hash_params.mask = 0x3fe0;
+ hash_params.shift = 5;
+}
+
+cache::~cache ()
+{
+ for (unsigned i = 0; i < sets.size (); i++)
+ delete sets[i];
+}
+
+cache_tag
+cache::addr_to_tag (const sid::host_int_4& addr) const
+{
+ return addr >> num_non_tag_bits;
+}
+
+sid::host_int_4
+cache::tag_to_addr (const cache_tag& tag) const
+{
+ return tag << num_non_tag_bits;
+}
+
+cache_line&
+cache::find (cache_tag tag, bool& hit)
+{
+ unsigned index = hash_fn (tag);
+ return sets[index]->find (tag, hit);
+}
+
+int
+cache::num_sets ()
+{
+ return sets.size ();
+}
+
+bool
+cache::vacancy_p (const sid::host_int_4& addr) const
+{
+ unsigned index = hash_fn (addr_to_tag (addr));
+ return sets[index]->vacancy_p ();
+}
+
+void
+cache::invalidate ()
+{
+ for (iterator_t it = sets.begin (); it != sets.end(); it++)
+ (*it)->invalidate ();
+}
+
+// Remove a line from the cache.
+void
+cache::expunge (cache_line& line)
+{
+ unsigned index = hash_fn (line.tag ());
+ sets[index]->expunge_line (line);
+}
+
+// Replace a line in the cache with 'new_line'. If the expelled
+// line is dirty, set 'old_line' to it and return true, otherwise
+// false.
+void
+cache::replace (cache_line& old_line, cache_line new_line)
+{
+ unsigned index = hash_fn (new_line.tag ());
+ return sets[index]->replace_line (old_line, new_line);
+}
+
+unsigned
+cache::hash_fn (const cache_tag& tag) const
+{
+ sid::host_int_4 addr = tag_to_addr (tag);
+ return (addr & hash_params.mask) >> hash_params.shift;
+}
+
+void
+cache::dump () const
+{
+ unsigned i = 0;
+ for (const_iterator_t it = sets.begin (); it != sets.end (); it++, i++)
+ {
+ cerr << "set " << i << endl;
+ (*it)->dump ();
+ }
+}
--- /dev/null
+// cacheutil.h -- Helper classes for a generic memory cache. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef CACHEUTIL_H
+#define CACHEUTIL_H
+
+#include <vector>
+#include <sidtypes.h>
+
+#include "log2.h"
+
+typedef sid::host_int_4 cache_tag;
+typedef sid::host_int_1 byte;
+
+// The cache_line class represents a line in a cache:
+
+// +-------+-----+----------------+ M = modified (dirty) bit
+// | M V L | tag | data | V = valid bit
+// +-------+-----+----------------+ L = lock bit
+// byte 0 N
+
+class cache_line
+{
+public:
+ cache_line (unsigned line_size);
+ cache_line (unsigned line_size, cache_tag tag);
+ cache_line (unsigned line_size, cache_tag tag, vector <byte> intial_data);
+ cache_line (const cache_line&);
+ cache_line& operator= (const cache_line&);
+ ~cache_line ();
+
+ // Get the line's tag.
+ cache_tag tag () const;
+
+ // Mark the line dirty or clean.
+ void dirty ();
+ void clean ();
+
+ // Mark the line valid or invalid.
+ void validate ();
+ void invalidate ();
+
+ // Lock or unlock the line.
+ void lock ();
+ void unlock ();
+
+ // Is the line dirty?
+ bool dirty_p () const;
+
+ // Is the line valid?
+ bool valid_p () const;
+
+ // Is the line locked?
+ bool locked_p () const;
+
+ // Insert a datum into the line, starting at byte offset.
+ template <typename DataType>
+ void insert (unsigned offset, DataType new_data)
+ {
+ assert (offset + sizeof (new_data) <= size);
+ typename DataType::value_type mem_image = new_data.target_memory_value ();
+ memcpy (& data[offset], & mem_image, sizeof (new_data));
+ dirty_bit = true;
+ }
+
+ // Extract a datum from the line, starting at byte offset.
+ template <typename DataType>
+ void extract (unsigned offset, DataType& new_data) const
+ {
+ assert (offset + sizeof (new_data) <= size);
+ typename DataType::value_type mem_image;
+ memcpy (& mem_image, & data[offset], sizeof (new_data));
+ new_data.set_target_memory_value (mem_image);
+ }
+
+ // Dump a line in human readable form to cout.
+ void dump () const;
+
+private:
+ unsigned size;
+ bool valid_bit;
+ bool dirty_bit;
+ bool lock_bit;
+ byte *data;
+ cache_tag atag;
+};
+
+// Allow cache tags and a line's cache tag to be compared directly.
+
+bool std::operator== (const cache_tag&, const cache_line&);
+bool std::operator== (const cache_line&, const cache_tag&);
+
+
+// A class from which all replacement algorithms should be derived.
+
+class cache_set;
+class cache_replacement_algorithm
+{
+public:
+ // Place new_line in a cache slot. Point old_line to the existing line.
+ // Return true if successful, false otherwise.
+ virtual void replace (cache_set& cset, cache_line& old_line, cache_line new_line) = 0;
+
+ // Update state (for example, treating LRU bits), if required.
+ virtual void update (cache_set& cset, cache_line& accessed_line) {}
+};
+
+
+// The cache_set class represents a set of cache_lines. For a 2-way
+// associative cache, there will be just two lines in the set.
+
+class cache_set
+{
+public:
+ cache_set (unsigned line_size, unsigned nlines,
+ cache_replacement_algorithm& alg);
+ ~cache_set ();
+
+ // Try to find a line in the cache with a matching tag.
+ // If found, set "hit" to true and return a ref to the line.
+ // Otherwise, set "hit" to false.
+ virtual cache_line& find (const cache_tag& tag, bool& hit);
+
+ // Invalidate the entire set.
+ void invalidate ();
+
+ // Is there any vacancy for a new line?
+ bool vacancy_p () const;
+
+ // Remove a line from the set.
+ void expunge_line (cache_line& line);
+
+ // Replace a line in the set with new_line.
+ // Return false if the line cannot be placed, true otherwise.
+ void replace_line (cache_line& old_line, cache_line new_line);
+
+ // Return the number of lines in the set.
+ unsigned num_lines () const;
+
+ // Get a cache line from slot `i' of the set.
+ cache_line& get_line (unsigned i) const;
+
+ // Place a cache line into slot `i' of the set.
+ void set_line (unsigned i, const cache_line line);
+
+ // Dump diagnostics to cerr.
+ virtual void dump () const;
+
+private:
+ cache_replacement_algorithm& replacer;
+ vector <cache_line*> lines;
+ typedef vector <cache_line*>::iterator iterator_t;
+ typedef vector <cache_line*>::const_iterator const_iterator_t;
+};
+
+\f
+// The cache class represents the complete cache as a series of
+// cache_sets. For a fully-associative cache, there will be one set
+// with many lines. For a direct mapped cache, there will be many
+// sets of single lines. Provide high-level methods for the user.
+
+// The constructor builds a cache cache_size bytes in size and of the
+// specified associativity. 0=fully assoc., 1=direct mapped, 2=2-way,
+// etc. The replacement algorithm is user-provided.
+
+class cache
+{
+public:
+ cache (unsigned cache_size, unsigned line_size,
+ unsigned assoc, cache_replacement_algorithm& replacer);
+ ~cache ();
+
+ // Calculate a tag.
+ cache_tag addr_to_tag (const sid::host_int_4& addr) const;
+
+ // Perform the inverse operation.
+ sid::host_int_4 tag_to_addr (const cache_tag& tag) const;
+
+ // Find a line, given a tag. If found, set hit to true and return it.
+ // Otherwise, set hit to false.
+ cache_line& find (cache_tag tag, bool& hit);
+
+ // Remove a line from the cache.
+ void expunge (cache_line& line);
+
+ // Vacancy in the cache?
+ bool vacancy_p (const sid::host_int_4& addr) const;
+
+ // Replace a line in the cache with 'new_line'. If the expelled
+ // line is dirty, set 'old_line' to it and return true, otherwise
+ // false.
+ void replace (cache_line& old_line, cache_line new_line);
+
+ // Invalidate the entire cache.
+ void invalidate ();
+
+ // The number of sets in the cache.
+ int num_sets ();
+
+ // Dump the entire cache's state.
+ void dump () const;
+
+ // index = (addr & mask) >> shift
+ struct
+ {
+ sid::host_int_4 mask;
+ unsigned shift;
+ } hash_params;
+
+private:
+ // Compute the index into the cache.
+ unsigned hash_fn (const cache_tag& tag) const;
+
+ // The number of non-tag bits in an address.
+ unsigned num_non_tag_bits;
+
+ vector <cache_set*> sets;
+ typedef vector <cache_set*>::iterator iterator_t;
+ typedef vector <cache_set*>::const_iterator const_iterator_t;
+};
+
+#endif // CACHEUTIL_H
--- /dev/null
+* 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.
--- /dev/null
+// log2.h -- Utility functions for power of two values. -*- C++ -*-
+
+// Copyright (C) 2001 Red Hat.
+// This file is part of SID and is licensed under the GPL.
+// See the file COPYING.SID for conditions for redistribution.
+
+#ifndef LOG2_H
+#define LOG2_H
+
+// Is V a power of two (ie. 32, 64)?
+
+template <typename V>
+bool power_of_two_p (const V& v1)
+{
+ int count = 0;
+ V v2(1);
+
+ for (int i = 0; i < 8 * sizeof (V); i++)
+ if (v1 & (v2 << i))
+ count++;
+
+ // Only one bit was set in v1.
+ return (count == 1);
+}
+
+// Compute log2 (V).
+
+template <typename V>
+int log2 (const V& v1)
+{
+ assert (power_of_two_p (v1));
+
+ V v2(1);
+ for (int i = 0; i < 8 * sizeof (V); i++)
+ if (v1 & (v2 << i))
+ return i;
+}
+
+#endif // LOG2_H
-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
ac_given_INSTALL="$INSTALL"
trap 'rm -fr `echo "Makefile testsuite/Makefile tconfig.h:tconfig.in siddoc
+ cache/Makefile
consoles/Makefile
gdb/Makefile
gloss/Makefile
cat >> $CONFIG_STATUS <<EOF
CONFIG_FILES=\${CONFIG_FILES-"Makefile testsuite/Makefile tconfig.h:tconfig.in siddoc
+ cache/Makefile
consoles/Makefile
gdb/Makefile
gloss/Makefile
dnl All other component subdirectories should be listed here, so "make"
dnl can recursively descend there - see "Makefile.am".
-make_subdirs="consoles gdb gloss glue ide interrupt lcd loader mapper memory mmu parport profiling rtc sched uart testsuite"
+make_subdirs="cache consoles gdb gloss glue ide interrupt lcd loader mapper memory mmu parport profiling rtc sched uart testsuite"
AC_SUBST(make_subdirs)
dnl List all component subdirectory files not covered by AC_CONFIG_SUBDIRS
dnl that need autoconf @substitution@.
AC_OUTPUT([Makefile testsuite/Makefile tconfig.h:tconfig.in siddoc
+ cache/Makefile
consoles/Makefile
gdb/Makefile
gloss/Makefile
+2001-06-15 Ben Elliston <bje@redhat.com>
+
+ * sidcomp.cache/cache.exp: New test case.
+ * sidcomp.cache/cachedocs.exp: Ditto.
+ * sidcomp.cache/cachemonkey.exp: Ditto.
+ * sidcomp.cache/coherency.exp: Ditto.
+ * sidcomp.cache/fifo.exp: Ditto.
+ * sidcomp.cache/flush.exp: Ditto.
+ * sidcomp.cache/lock.exp: Ditto.
+ * sidcomp.cache/lru.exp: Ditto.
+ * sidcomp.cache/misaligned.exp: Ditto.
+ * sidcomp.cache/prefetch.exp: Ditto.
+ * sidcomp.cache/random.exp: Ditto.
+ * sidcomp.cache/types.exp: Ditto.
+ * sidcomp.cache/utils.exp: Ditto.
+ * sidcomp.cache/writealloc.exp: Ditto.
+ * sidcomp.cache/writethru.exp: Ditto.
+
2001-06-13 Ben Elliston <bje@redhat.com>
* lib/docs.exp (doc_test): Pass $compname to doc_exists.
--- /dev/null
+# 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)
--- /dev/null
+load_lib "docs.exp"
+
+doc_test cache hw-cache-basic
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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
--- /dev/null
+# 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)" }
--- /dev/null
+# 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
--- /dev/null
+# 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)
+
--- /dev/null
+# 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
+
--- /dev/null
+# 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
--- /dev/null
+# 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
+ }
+}
--- /dev/null
+# 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}"
+ }
+ }
+}
--- /dev/null
+# 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
--- /dev/null
+# 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