Commit 7b84b49a authored by Gaurav Kukreja's avatar Gaurav Kukreja

Cache Simulator

Signed-off-by: Gaurav Kukreja's avatarGaurav Kukreja <gaurav@gauravk.in>
parent 00a7f918
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="cdt.managedbuild.config.gnu.lib.debug.1567375965">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.lib.debug.1567375965" moduleId="org.eclipse.cdt.core.settings" name="Debug">
<externalSettings>
<externalSetting>
<entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/cache_sim"/>
<entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/cache_sim/Debug"/>
<entry flags="RESOLVED" kind="libraryFile" name="cache_sim" srcPrefixMapping="" srcRootPath=""/>
</externalSetting>
</externalSettings>
<extensions>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactExtension="a" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.staticLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.staticLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.lib.debug.1567375965" name="Debug" parent="cdt.managedbuild.config.gnu.lib.debug">
<folderInfo id="cdt.managedbuild.config.gnu.lib.debug.1567375965." name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.lib.debug.1335207387" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.lib.debug">
<targetPlatform id="cdt.managedbuild.target.gnu.platform.lib.debug.432232652" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.lib.debug"/>
<builder buildPath="${workspace_loc:/cache_sim}/Debug" id="cdt.managedbuild.target.gnu.builder.lib.debug.1543884532" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.lib.debug"/>
<tool id="cdt.managedbuild.tool.gnu.archiver.lib.debug.1202500318" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.lib.debug"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.lib.debug.396479194" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.lib.debug">
<option id="gnu.cpp.compiler.lib.debug.option.optimization.level.716496815" name="Optimization Level" superClass="gnu.cpp.compiler.lib.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/>
<option id="gnu.cpp.compiler.lib.debug.option.debugging.level.1555157545" name="Debug Level" superClass="gnu.cpp.compiler.lib.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.compiler.lib.debug.569890370" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.lib.debug">
<option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.lib.debug.option.optimization.level.1476753283" name="Optimization Level" superClass="gnu.c.compiler.lib.debug.option.optimization.level" valueType="enumerated"/>
<option id="gnu.c.compiler.lib.debug.option.debugging.level.690149182" name="Debug Level" superClass="gnu.c.compiler.lib.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1967491996" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.256318858" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.337647535" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base"/>
<tool id="cdt.managedbuild.tool.gnu.assembler.lib.debug.568118199" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.lib.debug">
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1844715901" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
<cconfiguration id="cdt.managedbuild.config.gnu.lib.release.230985740">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.lib.release.230985740" moduleId="org.eclipse.cdt.core.settings" name="Release">
<externalSettings>
<externalSetting>
<entry flags="VALUE_WORKSPACE_PATH" kind="includePath" name="/cache_sim"/>
<entry flags="VALUE_WORKSPACE_PATH" kind="libraryPath" name="/cache_sim/Release"/>
<entry flags="RESOLVED" kind="libraryFile" name="cache_sim" srcPrefixMapping="" srcRootPath=""/>
</externalSetting>
</externalSettings>
<extensions>
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactExtension="a" artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.staticLib" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.staticLib" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.lib.release.230985740" name="Release" parent="cdt.managedbuild.config.gnu.lib.release">
<folderInfo id="cdt.managedbuild.config.gnu.lib.release.230985740." name="/" resourcePath="">
<toolChain id="cdt.managedbuild.toolchain.gnu.lib.release.1420794943" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.lib.release">
<targetPlatform id="cdt.managedbuild.target.gnu.platform.lib.release.1083796420" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.lib.release"/>
<builder buildPath="${workspace_loc:/cache_sim}/Release" id="cdt.managedbuild.target.gnu.builder.lib.release.332728705" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.lib.release"/>
<tool id="cdt.managedbuild.tool.gnu.archiver.lib.release.2072976079" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.lib.release"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.lib.release.467236594" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.lib.release">
<option id="gnu.cpp.compiler.lib.release.option.optimization.level.582962572" name="Optimization Level" superClass="gnu.cpp.compiler.lib.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/>
<option id="gnu.cpp.compiler.lib.release.option.debugging.level.1091499351" name="Debug Level" superClass="gnu.cpp.compiler.lib.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.compiler.lib.release.1568060851" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.lib.release">
<option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.lib.release.option.optimization.level.175392614" name="Optimization Level" superClass="gnu.c.compiler.lib.release.option.optimization.level" valueType="enumerated"/>
<option id="gnu.c.compiler.lib.release.option.debugging.level.1056650756" name="Debug Level" superClass="gnu.c.compiler.lib.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/>
<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.514621242" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
</tool>
<tool id="cdt.managedbuild.tool.gnu.c.linker.base.2133350279" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.789410493" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base"/>
<tool id="cdt.managedbuild.tool.gnu.assembler.lib.release.2009960156" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.lib.release">
<inputType id="cdt.managedbuild.tool.gnu.assembler.input.69254728" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
</tool>
</toolChain>
</folderInfo>
</configuration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="cache_sim.cdt.managedbuild.target.gnu.lib.50423431" name="Static Library" projectType="cdt.managedbuild.target.gnu.lib"/>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.lib.release.230985740;cdt.managedbuild.config.gnu.lib.release.230985740.;cdt.managedbuild.tool.gnu.c.compiler.lib.release.1568060851;cdt.managedbuild.tool.gnu.c.compiler.input.514621242">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.lib.debug.1567375965;cdt.managedbuild.config.gnu.lib.debug.1567375965.;cdt.managedbuild.tool.gnu.c.compiler.lib.debug.569890370;cdt.managedbuild.tool.gnu.c.compiler.input.1967491996">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>cache_simulator</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>
# Makefile for cache simulator
include Makefile.macros
check:
$(MAKE) -C $(SRC_DIR) TARGET_DIR=$(TEST_DIR) all
$(MAKE) -C $(TEST_DIR) all
$(TEST_DIR)/cacheSimTest
check_clean:
$(MAKE) -C $(TEST_DIR) clean
\ No newline at end of file
# Configuration for cache simulator
# Path to Cache Simulator
CSIM_DIR = /home/gaurav/eclipse-workspace/sls_thesis_project/cache_simulator
# No need to change
SRC_DIR = $(CSIM_DIR)/src
TEST_DIR = $(CSIM_DIR)/test
# Hardware Model to use
CACHESIM_HWMOD = generic
# Cache Simulation Source Code
SOURCES=cacheSim.c cacheSim.h cacheSimStat.c cacheSimStat.h cacheSimHwMod.h
# Add the source file(s) for the cache simulator hardware models
ifeq ($(CACHESIM_HWMOD),generic)
SOURCES += genericHwMod.c
endif
\ No newline at end of file
include ../Makefile.macros
# Default Target directory to install cache simulator. Will be over-rided.
TARGET_DIR = ../test
CP = cp
all:
$(CP) $(SOURCES) $(TARGET_DIR)
\ No newline at end of file
/**
* cache_sim.c
* Purpose: This is a cache simulation software. The benchmark code is
* instrumented, and the modified code is compiled with the simulator. The
* cache organization can be configured from human-readable config files.
*
* @author Gaurav Kukreja
*/
#include <stdio.h>
#include "cacheSimHwMod.h"
#include "cacheSimStat.h"
#define COLLECT_STAT
#define HERE printf("%s: %s: %d\n", __FILE__, __func__, __LINE__)
/******************************************************************************
* GLOBAL VARIABLES
******************************************************************************/
/******************************************************************************
* DATA STRUCTURES
******************************************************************************/
/******************************************************************************
* LOCAL FUNCTION DECLARATIONS
******************************************************************************/
/******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************/
/******************************************************************************
* GLOBAL FUNCTIONS
******************************************************************************/
/**
* Simulates Instruction Cache access by benchmark
*
* @param address Starting address of instructions in the basic block
* @param nBytes Number of bytes of instructions accessed in the basic block
*
* @return number of clock cycles spent
*/
unsigned int simICache(unsigned long address, unsigned int nBytes)
{
unsigned int nCycles;
cacheSimStat.access_type = ACCESS_TYPE_INVALID;
cacheSimStat.nCycles = 0;
cacheSimStat.powerMicroJ = 0;
nCycles = hwMod.simICache(address, nBytes);
#ifdef COLLECT_STAT
cacheSimStatCollect();
#endif
return nCycles;
}
/**
* Simulates Data Cache access by benchmark
*
* @param address Address of data accessed
*
* @return number of clock cycles spent
*/
unsigned int simDCache(unsigned long address, unsigned int isReadAccess)
{
unsigned int nCycles;
cacheSimStat.access_type = ACCESS_TYPE_INVALID;
cacheSimStat.nCycles = 0;
cacheSimStat.powerMicroJ = 0;
nCycles = hwMod.simDCache(address, isReadAccess);
#ifdef COLLECT_STAT
cacheSimStatCollect();
#endif
return nCycles;
}
/**
* Initialize the cache data structures
*/
void cacheSimInit()
{
hwMod.cacheSimInit();
}
/**
* Frees data structures and cleans up
*/
void cacheSimFini()
{
hwMod.cacheSimFini();
#ifdef COLLECT_STAT
cacheSimStatPrint();
#endif
}
/**
* cache_sim.h
* Purpose: Interface to the cache simulator. Defines functions that will be
* called from the benchmark.
*
* @author: Gaurav Kukreja
*/
#ifndef CACHE_SIM_H
#define CACHE_SIM_H
/**
* Simulates Instruction Cache access by benchmark
*
* @param address Starting address of instructions in the basic block
* @param nBytes Number of bytes of instructions accessed in the basic block
*
* @return number of clock cycles spent
*/
unsigned int simICache(unsigned long address, unsigned int nBytes);
/**
* Simulates Data Cache access by benchmark
*
* @param address Address of data accessed
* @param isReadAccess Tells cache simulator if it was read access.
*
* @return number of clock cycles spent
*/
unsigned int simDCache(unsigned long address, unsigned int isReadAccess);
/**
* Initialize the cache data structures
*/
void cacheSimInit();
/**
* Frees data structures and cleans up
*
*/
void cacheSimFini();
#endif // CACHE_SIM_H
/**
* cacheSimHwMod.h
* Purpose: Contains the Hardware Model Descriptor Data Structure
*
* @author: Gaurav Kukreja
*/
#ifndef CACHE_SIM_HW_MOD_H
#define CACHE_SIM_HW_MOD_H
#include "cacheSimStat.h"
/**
* Cache Simulation Hardware Model Descriptor
*/
struct cacheSimHwMod_t
{
/**
* Simulates Instruction Cache access by benchmark
*
* @param address Starting address of instructions in the basic block
* @param nBytes Number of bytes of instructions accessed in the basic block
*
* @return number of clock cycles spent
*/
unsigned int (*simICache) (unsigned long address, unsigned int nBytes);
/**
* Simulates Data Cache access by benchmark
*
* @param address Address of data accessed
* @param isReadAccess Tells cache simulator if it was read access.
*
* @return number of clock cycles spent
*/
unsigned int (*simDCache) (unsigned long address, unsigned int isReadAccess);
/**
* Initialize the cache data structures
*
* @param configFile Path to the json config file which describes cache
* organization
*/
void (*cacheSimInit) ();
/**
* Frees data structures and cleans up
*/
void (*cacheSimFini) ();
};
/**
* The hwMod data structure is a global data structure which will be defined in
* the hardware model implementations. It will be accessed from cacheSim.c by
* including this file, and be linked to the specific hardware model at compile
* time.
*/
extern struct cacheSimHwMod_t hwMod;
#endif // CACHE_SIM_HW_MOD_H
/**
* cacheSimStat.c
* Purpose: This code basically collects the results from cache simulation,
* and records the statistics for reporting later.
*/
#include <stdio.h>
#include "cacheSimStat.h"
/**
* Global Variable used to receive simulation statistics from HW Model
* Implementation.
*/
struct cacheSimStat_t cacheSimStat;
static unsigned long nAccesses = 0;
static unsigned long nL1Miss = 0;
static unsigned long nL1Hit = 0;
static unsigned long nL2Hit = 0;
static unsigned long nL2Miss = 0;
void cacheSimStatCollect()
{
nAccesses++;
switch(cacheSimStat.access_type)
{
case L1_HIT_READ:
case L1_HIT_WRITEBACK:
case L1_HIT_WRITETHROUGH:
nL1Hit++;
break;
case L1_MISS:
case L1_MISS_FLUSH:
nL1Miss++;
break;
case L2_HIT_READ:
case L2_HIT_WRITEBACK:
case L2_HIT_WRITETHROUGH:
nL1Miss++;
nL2Hit++;
break;
case L2_MISS:
case L2_MISS_FLUSH:
nL1Miss++;
nL2Miss++;
break;
default:
break;
}
}
void cacheSimStatPrint()
{
printf("Accesses = %lu \n"
"L1 Hits = %lu \n"
"L1 Miss = %lu (L1 Miss Rate = %lu) \n"
"L2 Hits = %lu \n"
"L2 Miss = %lu (L2 Miss Rate = %lu) \n",
nAccesses, nL1Hit, nL1Miss, nL1Miss*100/nAccesses,
nL2Hit, nL2Miss, nL2Miss*100/nAccesses);
}
/**
* cacheSimStat.h
* Purpose: Data structures and function declarations for collecting statistics
* returned from Cache Simulation.
*/
#ifndef CACHE_SIM_STAT_H
#define CACHE_SIM_STAT_H
/**
* Enum to specify the kind of memory access.
*/
enum cacheSimStatAccess_t
{
ACCESS_TYPE_INVALID = 0,
L1_HIT_READ,
L1_HIT_WRITEBACK,
L1_HIT_WRITETHROUGH,
L1_MISS_FLUSH,
L1_MISS,
L2_HIT_READ,
L2_HIT_WRITEBACK,
L2_HIT_WRITETHROUGH,
L2_MISS_FLUSH,
L2_MISS
};
/**
* Statistics will be returned by Hardware Model Implementation of the cache.
*/
struct cacheSimStat_t
{
enum cacheSimStatAccess_t access_type;
unsigned int nCycles;
unsigned int powerMicroJ;
};
/**
* cacheSimStat is globally declared in cacheSim.c. The Hardware Model
* implementation will use this data structure to return the cache simulation
* statistics.
*/
extern struct cacheSimStat_t cacheSimStat;
void cacheSimStatCollect();
void cacheSimStatPrint();
#endif // CACHE_SIM_STAT_H
/**
* genericHwMod.c
* Purpose: Implements a generic cache simulation hardware model
*
* The Generic Cache Model has the following features
*
* Levels
* It has two levels of Cache.
* L1 Cache has separate data and instruction caches. Set Associative Cache.
* L2 Cache is used for data as well as instruction.
*
* Size
* The cache size, cache line size and number of sets are initialized in
* readConfigFile() function.
*
* Features
* Write Through Cache
* No pre-fetching for data.
* No pre-fetching for instruction. (??)
* Round Robin Replacement Policy for L1
* No Special DMA effects have been taken into account
*
*/
#include <stdlib.h>
#include <string.h>
#include "cacheSimHwMod.h"
#include "cacheSimStat.h"
#define HERE printf("%s: %s: %d\n", __FILE__, __func__, __LINE__)
#define ADDRESS_LEN_BITS 32
#define CACHE_HIT 0
#define CACHE_HIT_WRITEBACK 1
#define CACHE_HIT_WRITETHROUGH 2
#define CACHE_MISS 3
#define CACHE_MISS_FLUSH 4
/******************************************************************************
* DATA STRUCTURES
******************************************************************************/
/**
* Stores cache parameters for each type/level of cache
*/
struct cacheParam_t
{
// Size Params
unsigned int cacheSets;
unsigned int cacheSizeBytes;
unsigned int lineSizeBytes;
unsigned int cacheLength;
unsigned int tagLengthBits;
unsigned int indexLengthBits;
unsigned int offsetLengthBits;
// Derived
unsigned long tagMask;
unsigned long indexMask;
// Features
unsigned int isWriteThrough;
// Latencies
unsigned int latHitRead;
unsigned int latHitWriteThrough;
unsigned int latHitWriteBack;
unsigned int latMiss;
unsigned int latMissFlush;
};
#define CACHELINE_VALID_BIT (1 << 0)
#define IS_CACHELINE_VALID(flags) (flags & CACHELINE_VALID_BIT)
#define SET_CACHELINE_VALID(flags) (flags |= CACHELINE_VALID_BIT)
#define SET_CACHELINE_INVALID(flags) (flags &= ~CACHELINE_VALID_BIT)
#define CACHELINE_DIRTY_BIT (1 << 1)
#define IS_CACHELINE_DIRTY(flags) (flags & CACHELINE_DIRTY_BIT)
#define SET_CACHELINE_DIRTY(flags) (flags |= CACHELINE_DIRTY_BIT)
#define SET_CACHELINE_CLEAN(flags) (flags &= ~CACHELINE_DIRTY_BIT)
/**
* Stores all data related to a cache line.
*/
struct cacheLine_t
{
unsigned int flags;
unsigned long tag;
};
/******************************************************************************
* GLOBAL VARIABLES
******************************************************************************/
struct cacheParam_t L1Params;
struct cacheParam_t L2Params;
struct cacheLine_t **L1DCache;
struct cacheLine_t **L1ICache;
struct cacheLine_t **L2DCache;
struct cacheLine_t **L2ICache;
/**
* Array to keep a track of which cache line to remove in a round robin fashion
*/
unsigned int *L1DCacheReplace;
unsigned int *L1ICacheReplace;
unsigned int *L2DCacheReplace;
unsigned int *L2ICacheReplace;
/******************************************************************************
* LOCAL FUNCTION DECLARATIONS
******************************************************************************/
unsigned int generic_simL1DCache(unsigned long address,
unsigned int isReadAcccess);
void readConfigFile();
void** alloc2D(unsigned int rows, unsigned int cols, size_t size);
/******************************************************************************
* LOCAL FUNCTIONS
******************************************************************************/
/**
* Reads config file and initializes data structures
*
* @param configFile Path to the config file.
*/
void readConfigFile()
{
// TODO: Read from config file, and remove the following workaround
int i;
// L1 Cache Parameters - same for separate Instruction and Data Cache
// L1 Size Params
L1Params.cacheSets = 4;
L1Params.cacheSizeBytes = 16 * 1024; // 16 KB
L1Params.lineSizeBytes = 16;
L1Params.tagLengthBits = 20;
L1Params.indexLengthBits = 8; // 256 lines
L1Params.offsetLengthBits = 4; // 16B cache lines
// L1 Latencies
L1Params.latHitRead = 2;
L1Params.latHitWriteThrough = 100;
L1Params.latHitWriteBack = 4;
L1Params.latMiss = 2;
L1Params.latMissFlush = 105;
// L1 Features
L1Params.isWriteThrough = 1;
// L1 Derived
L1Params.cacheLength = L1Params.cacheSizeBytes
/ L1Params.cacheSets
/ L1Params.lineSizeBytes; //256
L1Params.tagMask = 0;
for(i=0; i < L1Params.tagLengthBits; i++)
{
L1Params.tagMask = L1Params.tagMask << 1;
L1Params.tagMask = L1Params.tagMask | 0x00000001;
}
L1Params.tagMask = L1Params.tagMask << (32 - L1Params.tagLengthBits);
L1Params.indexMask = 0;
for(i=0; i < L1Params.indexLengthBits; i++)
{
L1Params.indexMask = L1Params.indexMask << 1;
L1Params.indexMask = L1Params.indexMask | 0x00000001;
}
L1Params.indexMask = L1Params.indexMask << L1Params.offsetLengthBits;
///////////////////////////////////////////////
// L2 Cache Parameters - unified cache for data and instruction
// L2 Size Params
L2Params.cacheSets = 8;
L2Params.cacheSizeBytes = 256 * 1024;
L2Params.lineSizeBytes = 64;
L2Params.tagLengthBits = 17;
L2Params.indexLengthBits = 9; // 512 lines
L2Params.offsetLengthBits = 6; // 64B cache lines
// L2 Latencies
L2Params.latHitRead = 20;
L2Params.latHitWriteThrough = 100;
L2Params.latHitWriteBack = 25;
L2Params.latMiss = 20;
L2Params.latMissFlush = 120;
// L2 Features
L2Params.isWriteThrough = 1;
// L2 Derived
L2Params.cacheLength = L2Params.cacheSizeBytes
/ L2Params.cacheSets
/ L2Params.lineSizeBytes; // 512
L2Params.tagMask = 0;
for(int i=0; i < L2Params.tagLengthBits; i++)
{
L2Params.tagMask = L2Params.tagMask << 1;
L2Params.tagMask = L2Params.tagMask | 0x00000001;
}
L2Params.tagMask = L2Params.tagMask << (32 - L2Params.tagLengthBits);
L2Params.indexMask = 0;
for(int i=0; i < L2Params.indexLengthBits; i++)
{
L2Params.indexMask = L2Params.indexMask << 1;
L2Params.indexMask = L2Params.indexMask | 0x00000001;
}
L2Params.indexMask = L2Params.indexMask << L2Params.offsetLengthBits;
//////////////////////////////////////////////////
}
/**
* Allocates a 2 dimensional array. To be used to allocate space for cache lines
*
* @param rows number of rows
* @param cols number of cols
* @param size size of the data structure to be stored
*
* @return pointer to array of pointers pointing to rows of data.
*/
void** alloc2D(unsigned int rows, unsigned int cols, size_t size)
{
void** ret;
void *data;
int i;
size_t arrSize = (rows * sizeof(void*)) + (rows * cols * size);
ret = malloc(arrSize);
memset(ret, 0, arrSize);
data = (void*) (ret + rows);
for(i=0; i<rows; i++)
{
ret[i] = data + i * cols * size;
}
return ret;
}
inline unsigned long getTagFromAddress(unsigned long address,
unsigned int tagLengthBits, unsigned long tagMask)
{
return (address & tagMask) >> (ADDRESS_LEN_BITS - tagLengthBits);
}
inline unsigned long getIndexFromAddress(unsigned long address,
unsigned int offsetLengthBits, unsigned long indexMask)
{
return (address & indexMask) >> offsetLengthBits;
}
unsigned int generic_simL2ICache(unsigned long address,
unsigned int isReadAcccess)
{
unsigned long index;
unsigned long tag;
int replaceSet = -1;
tag = getTagFromAddress(address, L2Params.tagLengthBits,
L2Params.tagMask);
index = getIndexFromAddress(address, L2Params.offsetLengthBits,
L2Params.indexMask);
for(int set = 0; set < L2Params.cacheSets; set++)
{
if(L2ICache[set][index].tag == tag &&
(IS_CACHELINE_VALID(L2ICache[set][index].flags))) // L2 HIT
{
if(!isReadAcccess) // Write Access
{
if(L2Params.isWriteThrough) // Write Through
{
// Data in L2 will be updated, and will remain VALID -
// nothing to do
// Some cycles wasted for data flush
cacheSimStat.access_type = L2_HIT_WRITETHROUGH;
cacheSimStat.nCycles += L2Params.latHitWriteThrough;
return CACHE_HIT_WRITETHROUGH;
}
else // Write Back
{
// Data in L2 will be updated, and will remain VALID. Line
// will be marked for flush - nothing to do
// No extra cycles wasted now for flush
cacheSimStat.access_type = L2_HIT_WRITEBACK;
cacheSimStat.nCycles += L2Params.latHitWriteBack;
return CACHE_HIT_WRITEBACK;
}
}
else // Read Access
{
// Nothing to do, no cycles spent
cacheSimStat.access_type = L2_HIT_READ;
cacheSimStat.nCycles += L2Params.latHitRead;
return CACHE_HIT;
}
}
if (replaceSet == -1 && !(IS_CACHELINE_VALID (L2ICache[set][index].flags)))
replaceSet = set;
}
// Cache Miss Occurred
if (replaceSet == -1)
{
replaceSet = L2ICacheReplace[index];
L2ICacheReplace[index] = (L2ICacheReplace[index] == 7) ? 0 : L2ICacheReplace[index]+1;
}
if(IS_CACHELINE_DIRTY (L2ICache[replaceSet][index].flags))
{
// !! Should never occur, since we are using Write Through Cache.
// Flush the cache line - nothing to do specifically, just add the
// extra nCycles wasted in this case.
// Already, load new data assuming it will be fetched from L2 or Mem
L2ICache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L2ICache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L2ICache[replaceSet][index].flags);
cacheSimStat.access_type = L2_MISS_FLUSH;
cacheSimStat.nCycles += L2Params.latMissFlush;
return CACHE_MISS_FLUSH;
}
else
{
// Evict cache line - nothing to do. No cycles wasted.
// Already, load new data assuming it will be fetched from L2 or Mem
L2ICache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L2ICache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L2ICache[replaceSet][index].flags);
cacheSimStat.access_type = L2_MISS;
cacheSimStat.nCycles += L2Params.latMiss;
return CACHE_MISS;
}
}
unsigned int generic_simL1ICache(unsigned long address,
unsigned int isReadAcccess)
{
unsigned long index;
unsigned long tag;
int replaceSet = -1;
tag = getTagFromAddress(address, L1Params.tagLengthBits,
L1Params.tagMask);
index = getIndexFromAddress(address, L1Params.offsetLengthBits,
L1Params.indexMask);
for(int set = 0; set < L1Params.cacheSets; set++)
{
if(L1ICache[set][index].tag == tag &&
(IS_CACHELINE_VALID(L1ICache[set][index].flags))) // L1 HIT
{
if(!isReadAcccess) // Write Access
{
if(L1Params.isWriteThrough) // Write Through
{
// Data in L1 will be updated, and will remain VALID -
// nothing to do
// Some cycles wasted for data flush
cacheSimStat.access_type = L1_HIT_WRITETHROUGH;
cacheSimStat.nCycles += L1Params.latHitWriteThrough;
return CACHE_HIT_WRITETHROUGH;
}
else // Write Back
{
// Data in L1 will be updated, and will remain VALID. Line
// will be marked for flush - nothing to do
// No extra cycles wasted now for flush
cacheSimStat.access_type = L1_HIT_WRITEBACK;
cacheSimStat.nCycles += L1Params.latHitWriteBack;
return CACHE_HIT_WRITEBACK;
}
}
else // Read Access
{
// Nothing to do, no cycles spent
cacheSimStat.access_type = L1_HIT_READ;
cacheSimStat.nCycles += L1Params.latHitRead;
return CACHE_HIT;
}
}
if (replaceSet == -1 && !(IS_CACHELINE_VALID (L1ICache[set][index].flags)))
replaceSet = set;
}
// Cache Miss Occurred
if (replaceSet == -1)
{
replaceSet = L1ICacheReplace[index];
L1ICacheReplace[index] = (L1ICacheReplace[index] == 3) ? 0 : L1ICacheReplace[index]+1;
}
if(IS_CACHELINE_DIRTY (L1ICache[replaceSet][index].flags))
{
// !! Should never occur, since we are using Write Through Cache.
// Flush the cache line - nothing to do specifically, just add the
// extra nCycles wasted in this case.
// Already, load new data assuming it will be fetched from L2 or Mem
L1ICache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L1ICache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L1ICache[replaceSet][index].flags);
cacheSimStat.access_type = L1_MISS_FLUSH;
cacheSimStat.nCycles += L1Params.latMissFlush;
return CACHE_MISS_FLUSH;
}
else
{
// Evict cache line - nothing to do. No cycles wasted.
// Already, load new data assuming it will be fetched from L2 or Mem
L1ICache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L1ICache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L1ICache[replaceSet][index].flags);
cacheSimStat.access_type = L1_MISS;
cacheSimStat.nCycles += L1Params.latMiss;
return CACHE_MISS;
}
}
/**
* Simulates Instruction Cache access by benchmark
*
* @param address Starting address of instructions in the basic block
* @param nBytes Number of bytes of instructions accessed in the basic block
*
* @return number of clock cycles spent
*/
unsigned int generic_simICache(unsigned long address, unsigned int nBytes)
{
unsigned int nCycles;
return nCycles;
}
unsigned int generic_simL2DCache(unsigned long address,
unsigned int isReadAcccess)
{
unsigned long index;
unsigned long tag;
int replaceSet = -1;
tag = getTagFromAddress(address, L2Params.tagLengthBits,
L2Params.tagMask);
index = getIndexFromAddress(address, L2Params.offsetLengthBits,
L2Params.indexMask);
for(int set = 0; set < L2Params.cacheSets; set++)
{
if(L2DCache[set][index].tag == tag &&
(IS_CACHELINE_VALID(L2DCache[set][index].flags))) // L2 HIT
{
if(!isReadAcccess) // Write Access
{
if(L2Params.isWriteThrough) // Write Through
{
// Data in L2 will be updated, and will remain VALID -
// nothing to do
// Some cycles wasted for data flush
cacheSimStat.access_type = L2_HIT_WRITETHROUGH;
cacheSimStat.nCycles += L2Params.latHitWriteThrough;
return CACHE_HIT_WRITETHROUGH;
}
else // Write Back
{
// Data in L2 will be updated, and will remain VALID. Line
// will be marked for flush - nothing to do
// No extra cycles wasted now for flush
cacheSimStat.access_type = L2_HIT_WRITEBACK;
cacheSimStat.nCycles += L2Params.latHitWriteBack;
return CACHE_HIT_WRITEBACK;
}
}
else // Read Access
{
// Nothing to do, no cycles spent
cacheSimStat.access_type = L2_HIT_READ;
cacheSimStat.nCycles += L2Params.latHitRead;
return CACHE_HIT;
}
}
if (replaceSet == -1 && !(IS_CACHELINE_VALID (L2DCache[set][index].flags)))
replaceSet = set;
}
// Cache Miss Occurred
if (replaceSet == -1)
{
replaceSet = L2DCacheReplace[index];
L2DCacheReplace[index] = (L2DCacheReplace[index] == 7) ? 0 : L2DCacheReplace[index]+1;
}
if(IS_CACHELINE_DIRTY (L2DCache[replaceSet][index].flags))
{
// !! Should never occur, since we are using Write Through Cache.
// Flush the cache line - nothing to do specifically, just add the
// extra nCycles wasted in this case.
// Already, load new data assuming it will be fetched from L2 or Mem
L2DCache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L2DCache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L2DCache[replaceSet][index].flags);
cacheSimStat.access_type = L2_MISS_FLUSH;
cacheSimStat.nCycles += L2Params.latMissFlush;
return CACHE_MISS_FLUSH;
}
else
{
// Evict cache line - nothing to do. No cycles wasted.
// Already, load new data assuming it will be fetched from L2 or Mem
L2DCache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L2DCache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L2DCache[replaceSet][index].flags);
cacheSimStat.access_type = L2_MISS;
cacheSimStat.nCycles += L2Params.latMiss;
return CACHE_MISS;
}
}
unsigned int generic_simL1DCache(unsigned long address,
unsigned int isReadAcccess)
{
unsigned long index;
unsigned long tag;
int replaceSet = -1;
tag = getTagFromAddress(address, L1Params.tagLengthBits,
L1Params.tagMask);
index = getIndexFromAddress(address, L1Params.offsetLengthBits,
L1Params.indexMask);
for(int set = 0; set < L1Params.cacheSets; set++)
{
if(L1DCache[set][index].tag == tag &&
(IS_CACHELINE_VALID(L1DCache[set][index].flags))) // L1 HIT
{
if(!isReadAcccess) // Write Access
{
if(L1Params.isWriteThrough) // Write Through
{
// Data in L1 will be updated, and will remain VALID -
// nothing to do
// Some cycles wasted for data flush
cacheSimStat.access_type = L1_HIT_WRITETHROUGH;
cacheSimStat.nCycles += L1Params.latHitWriteThrough;
return CACHE_HIT_WRITETHROUGH;
}
else // Write Back
{
// Data in L1 will be updated, and will remain VALID. Line
// will be marked for flush - nothing to do
// No extra cycles wasted now for flush
cacheSimStat.access_type = L1_HIT_WRITEBACK;
cacheSimStat.nCycles += L1Params.latHitWriteBack;
return CACHE_HIT_WRITEBACK;
}
}
else // Read Access
{
// Nothing to do, no cycles spent
cacheSimStat.access_type = L1_HIT_READ;
cacheSimStat.nCycles += L1Params.latHitRead;
return CACHE_HIT;
}
}
if (replaceSet == -1 && !(IS_CACHELINE_VALID (L1DCache[set][index].flags)))
replaceSet = set;
}
// Cache Miss Occurred
if (replaceSet == -1)
{
replaceSet = L1DCacheReplace[index];
L1DCacheReplace[index] = (L1DCacheReplace[index] == 3) ? 0 : L1DCacheReplace[index]+1;
}
if(IS_CACHELINE_DIRTY (L1DCache[replaceSet][index].flags))
{
// !! Should never occur, since we are using Write Through Cache.
// Flush the cache line - nothing to do specifically, just add the
// extra nCycles wasted in this case.
// Already, load new data assuming it will be fetched from L2 or Mem
L1DCache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L1DCache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L1DCache[replaceSet][index].flags);
cacheSimStat.access_type = L1_MISS_FLUSH;
cacheSimStat.nCycles += L1Params.latMissFlush;
return CACHE_MISS_FLUSH;
}
else
{
// Evict cache line - nothing to do. No cycles wasted.
// Already, load new data assuming it will be fetched from L2 or Mem
L1DCache[replaceSet][index].tag = tag;
SET_CACHELINE_VALID (L1DCache[replaceSet][index].flags);
SET_CACHELINE_CLEAN (L1DCache[replaceSet][index].flags);
cacheSimStat.access_type = L1_MISS;
cacheSimStat.nCycles += L1Params.latMiss;
return CACHE_MISS;
}
}
/**
* Simulates Data Cache access by benchmark
*
* @param address Address of data accessed
*
* @return number of clock cycles spent
*/
unsigned int generic_simDCache(unsigned long address, unsigned int isReadAccess)
{
unsigned int nCycles;
unsigned int ret;
ret = generic_simL1DCache(address, isReadAccess);
if(CACHE_MISS == ret || CACHE_MISS_FLUSH == ret)
{
// L1 Data Cache Miss has occured, simulate L2 Access.
ret = generic_simL2DCache(address, isReadAccess);
if(CACHE_MISS == ret || CACHE_MISS_FLUSH == ret)
{
cacheSimStat.nCycles += 100;
}
}
return nCycles;
}
/**
* Initialize the cache data structures
*/
void generic_cacheSimInit()
{
readConfigFile();
// allocating space for storing the cache lines in a 2d array
// L1 Data cache
L1DCache = (struct cacheLine_t **) alloc2D (L1Params.cacheSets,
L1Params.cacheLength, sizeof(struct cacheLine_t));
L1DCacheReplace = (unsigned int *) malloc((size_t) L1Params.cacheLength *
sizeof(unsigned int));
// L1 Instruction Cache
L1ICache = (struct cacheLine_t **) alloc2D (L1Params.cacheSets,
L1Params.cacheLength, sizeof(struct cacheLine_t));
L1ICacheReplace = (unsigned int *) malloc((size_t) L1Params.cacheLength *
sizeof(unsigned int));
// L2 Data Cache
L2DCache = (struct cacheLine_t **) alloc2D (L2Params.cacheSets,
L2Params.cacheLength, sizeof(struct cacheLine_t));
L2DCacheReplace = (unsigned int *) malloc((size_t) L2Params.cacheLength *
sizeof(unsigned int));
// L2 Instruction Cache
L2ICache = (struct cacheLine_t **) alloc2D (L2Params.cacheSets,
L2Params.cacheLength, sizeof(struct cacheLine_t));
L2ICacheReplace = (unsigned int *) malloc((size_t) L2Params.cacheLength *
sizeof(unsigned int));
}
/**
* Frees data structures and cleans up
*
*/
void generic_cacheSimFini()
{
free(L1DCache);
}
struct cacheSimHwMod_t hwMod = {
.simDCache = &generic_simDCache,
.simICache = &generic_simICache,
.cacheSimInit = &generic_cacheSimInit,
.cacheSimFini = &generic_cacheSimFini
};
include ../Makefile.macros
CC=gcc
CFLAGS=-O2 -std=c99
TEST_SOURCES = cacheSimTest.c
all: cacheSimTest
cacheSimTest: $(SOURCES) $(TEST_SOURCES)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -rf *.o cacheSimTest
for f in $(SOURCES); do \
rm -rf $$f; \
done
\ No newline at end of file
/**
* This program tests the cache simulation software. It basically generates a
* number of memory accesses, and checks the statistics generated from cache
* simulation.
*/
#include "cacheSim.h"
#define HERE printf("%s: %s: %d\n", __FILE__, __func__, __LINE__)
#define MAX_REPEATS 2
#define MAX_ACCESSES 524288
#define START_ADD 0x12345678
int main(int argc, char **argv)
{
unsigned long address = START_ADD;
cacheSimInit();
for(unsigned long j = 0; j < MAX_REPEATS; j++)
for(unsigned long i = 0; i < MAX_ACCESSES; i++)
{
simDCache(address + i, 1);
}
cacheSimFini();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment