summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorBrad Beckmann <Brad.Beckmann@amd.com>2012-07-10 22:51:54 -0700
committerBrad Beckmann <Brad.Beckmann@amd.com>2012-07-10 22:51:54 -0700
commit86d6b788f6d7b523c750ffb64d6d8920ec741c49 (patch)
tree2d6be00e66218b39bae31a27380a47283f70c097 /src/mem
parent467093ebf238a1954e00576daf14a9f246b51e79 (diff)
downloadgem5-86d6b788f6d7b523c750ffb64d6d8920ec741c49.tar.xz
ruby: banked cache array resource model
This patch models a cache as separate tag and data arrays. The patch exposes the banked array as another resource that is checked by SLICC before a transition is allowed to execute. This is similar to how TBE entries and slots in output ports are modeled.
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/SConscript1
-rw-r--r--src/mem/protocol/RubySlicc_Exports.sm5
-rw-r--r--src/mem/protocol/RubySlicc_Types.sm2
-rw-r--r--src/mem/ruby/system/BankedArray.cc57
-rw-r--r--src/mem/ruby/system/BankedArray.hh47
-rw-r--r--src/mem/ruby/system/Cache.py6
-rw-r--r--src/mem/ruby/system/CacheMemory.cc44
-rw-r--r--src/mem/ruby/system/CacheMemory.hh10
-rw-r--r--src/mem/ruby/system/SConscript1
-rw-r--r--src/mem/slicc/symbols/StateMachine.py8
10 files changed, 180 insertions, 1 deletions
diff --git a/src/mem/SConscript b/src/mem/SConscript
index caa7fe501..d290da875 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -86,6 +86,7 @@ DebugFlag('RubySlicc')
DebugFlag('RubySystem')
DebugFlag('RubyTester')
DebugFlag('RubyStats')
+DebugFlag('RubyResourceStalls')
CompoundFlag('Ruby', [ 'RubyQueue', 'RubyNetwork', 'RubyTester',
'RubyGenerated', 'RubySlicc', 'RubySystem', 'RubyCache',
diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm
index ef752c604..92739385b 100644
--- a/src/mem/protocol/RubySlicc_Exports.sm
+++ b/src/mem/protocol/RubySlicc_Exports.sm
@@ -184,6 +184,11 @@ enumeration(CacheRequestType, desc="...", default="CacheRequestType_NULL") {
TagArrayWrite, desc="Write access to the cache's tag array";
}
+enumeration(CacheResourceType, desc="...", default="CacheResourceType_NULL") {
+ DataArray, desc="Access to the cache's data array";
+ TagArray, desc="Access to the cache's tag array";
+}
+
enumeration(DirectoryRequestType, desc="...", default="DirectoryRequestType_NULL") {
Default, desc="Replace this with access_types passed to the Directory Ruby object";
}
diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm
index 436b39273..a14af946c 100644
--- a/src/mem/protocol/RubySlicc_Types.sm
+++ b/src/mem/protocol/RubySlicc_Types.sm
@@ -109,6 +109,7 @@ structure (Sequencer, external = "yes") {
void profileNack(Address, int, int, uint64);
void evictionCallback(Address);
void recordRequestType(SequencerRequestType);
+ bool checkResourceAvailable(CacheResourceType, Address);
}
structure(RubyRequest, desc="...", interface="Message", external="yes") {
@@ -154,6 +155,7 @@ structure (CacheMemory, external = "yes") {
void setMRU(Address);
void recordRequestType(CacheRequestType);
+ bool checkResourceAvailable(CacheResourceType, Address);
}
structure (WireBuffer, inport="yes", outport="yes", external = "yes") {
diff --git a/src/mem/ruby/system/BankedArray.cc b/src/mem/ruby/system/BankedArray.cc
new file mode 100644
index 000000000..3113393a1
--- /dev/null
+++ b/src/mem/ruby/system/BankedArray.cc
@@ -0,0 +1,57 @@
+
+
+#include <vector>
+
+#include "base/intmath.hh"
+#include "mem/ruby/common/TypeDefines.hh"
+#include "mem/ruby/system/BankedArray.hh"
+#include "sim/eventq.hh"
+
+BankedArray::BankedArray(unsigned int banks, unsigned int accessLatency, unsigned int startIndexBit) :
+ EventManager(&mainEventQueue)
+{
+ this->banks = banks;
+ this->accessLatency = accessLatency;
+ this->startIndexBit = startIndexBit;
+
+ if (banks != 0) {
+ bankBits = floorLog2(banks);
+ }
+
+ busyBanks.resize(banks);
+}
+
+bool
+BankedArray::tryAccess(Index idx)
+{
+ if (accessLatency == 0)
+ return true;
+
+ unsigned int bank = mapIndexToBank(idx);
+ assert(bank < banks);
+
+ if (busyBanks[bank].scheduled()) {
+ if (!(busyBanks[bank].startAccess == curTick() && busyBanks[bank].idx == idx)) {
+ return false;
+ } else {
+ return true; // We tried to allocate resources twice in the same cycle for the same addr
+ }
+ }
+
+ busyBanks[bank].idx = idx;
+ busyBanks[bank].startAccess = curTick();
+
+ // substract 1 so that next cycle the resource available
+ schedule(busyBanks[bank], curTick()+accessLatency-1);
+
+ return true;
+}
+
+unsigned int
+BankedArray::mapIndexToBank(Index idx)
+{
+ if (banks == 1) {
+ return 0;
+ }
+ return idx % banks;
+}
diff --git a/src/mem/ruby/system/BankedArray.hh b/src/mem/ruby/system/BankedArray.hh
new file mode 100644
index 000000000..2db4d3d95
--- /dev/null
+++ b/src/mem/ruby/system/BankedArray.hh
@@ -0,0 +1,47 @@
+
+#ifndef __MEM_RUBY_SYSTEM_BANKEDARRAY_HH__
+#define __MEM_RUBY_SYSTEM_BANKEDARRAY_HH__
+
+#include <vector>
+
+#include "mem/ruby/common/TypeDefines.hh"
+#include "sim/eventq.hh"
+
+
+
+class BankedArray : public EventManager
+{
+private:
+ unsigned int banks;
+ unsigned int accessLatency;
+ unsigned int bankBits;
+ unsigned int startIndexBit;
+
+ //std::vector<bool> busyBanks;
+
+ class TickEvent : public Event
+ {
+ public:
+ TickEvent() : Event() {}
+ void process() {}
+ Index idx;
+ Tick startAccess;
+ };
+ friend class TickEvent;
+
+ // If the tick event is scheduled then the bank is busy
+ // otherwise, schedule the event and wait for it to complete
+ std::vector<TickEvent> busyBanks;
+
+ unsigned int mapIndexToBank(Index idx);
+
+public:
+ BankedArray(unsigned int banks, unsigned int accessLatency, unsigned int startIndexBit);
+
+ // Note: We try the access based on the cache index, not the address
+ // This is so we don't get aliasing on blocks being replaced
+ bool tryAccess(Index idx);
+
+};
+
+#endif
diff --git a/src/mem/ruby/system/Cache.py b/src/mem/ruby/system/Cache.py
index 79ab9b070..2b4daa68b 100644
--- a/src/mem/ruby/system/Cache.py
+++ b/src/mem/ruby/system/Cache.py
@@ -40,3 +40,9 @@ class RubyCache(SimObject):
replacement_policy = Param.String("PSEUDO_LRU", "");
start_index_bit = Param.Int(6, "index start, default 6 for 64-byte line");
is_icache = Param.Bool(False, "is instruction only cache");
+
+ dataArrayBanks = Param.Int(1, "Number of banks for the data array")
+ tagArrayBanks = Param.Int(1, "Number of banks for the tag array")
+ dataAccessLatency = Param.Int(1, "Gem5 cycles for the data array")
+ tagAccessLatency = Param.Int(1, "Gem5 cycles for the tag array")
+ resourceStalls = Param.Bool(False, "stall if there is a resource failure")
diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc
index a626dc13f..a8e3523d3 100644
--- a/src/mem/ruby/system/CacheMemory.cc
+++ b/src/mem/ruby/system/CacheMemory.cc
@@ -29,6 +29,7 @@
#include "base/intmath.hh"
#include "debug/RubyCache.hh"
#include "debug/RubyCacheTrace.hh"
+#include "debug/RubyResourceStalls.hh"
#include "debug/RubyStats.hh"
#include "mem/protocol/AccessPermission.hh"
#include "mem/ruby/system/CacheMemory.hh"
@@ -51,7 +52,9 @@ RubyCacheParams::create()
}
CacheMemory::CacheMemory(const Params *p)
- : SimObject(p)
+ : SimObject(p),
+ dataArray(p->dataArrayBanks, p->dataAccessLatency, p->start_index_bit),
+ tagArray(p->tagArrayBanks, p->tagAccessLatency, p->start_index_bit)
{
m_cache_size = p->size;
m_latency = p->latency;
@@ -60,6 +63,7 @@ CacheMemory::CacheMemory(const Params *p)
m_profiler_ptr = new CacheProfiler(name());
m_start_index_bit = p->start_index_bit;
m_is_instruction_only_cache = p->is_icache;
+ m_resource_stalls = p->resourceStalls;
}
void
@@ -523,4 +527,42 @@ CacheMemory::regStats() {
.name(name() + ".num_tag_array_writes")
.desc("number of tag array writes")
;
+
+ numTagArrayStalls
+ .name(name() + ".num_tag_array_stalls")
+ .desc("number of stalls caused by tag array")
+ ;
+
+ numDataArrayStalls
+ .name(name() + ".num_data_array_stalls")
+ .desc("number of stalls caused by data array")
+ ;
}
+
+bool
+CacheMemory::checkResourceAvailable(CacheResourceType res, Address addr)
+{
+ if (!m_resource_stalls) {
+ return true;
+ }
+
+ if (res == CacheResourceType_TagArray) {
+ if (tagArray.tryAccess(addressToCacheSet(addr))) return true;
+ else {
+ DPRINTF(RubyResourceStalls, "Tag array stall on addr %s in set %d\n", addr, addressToCacheSet(addr));
+ numTagArrayStalls++;
+ return false;
+ }
+ } else if (res == CacheResourceType_DataArray) {
+ if (dataArray.tryAccess(addressToCacheSet(addr))) return true;
+ else {
+ DPRINTF(RubyResourceStalls, "Data array stall on addr %s in set %d\n", addr, addressToCacheSet(addr));
+ numDataArrayStalls++;
+ return false;
+ }
+ } else {
+ assert(false);
+ return true;
+ }
+}
+
diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh
index 53cd6b286..ee3c1a7fc 100644
--- a/src/mem/ruby/system/CacheMemory.hh
+++ b/src/mem/ruby/system/CacheMemory.hh
@@ -35,6 +35,7 @@
#include "base/hashmap.hh"
#include "base/statistics.hh"
+#include "mem/protocol/CacheResourceType.hh"
#include "mem/protocol/CacheRequestType.hh"
#include "mem/protocol/GenericRequestType.hh"
#include "mem/protocol/RubyRequest.hh"
@@ -43,6 +44,7 @@
#include "mem/ruby/recorder/CacheRecorder.hh"
#include "mem/ruby/slicc_interface/AbstractCacheEntry.hh"
#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
+#include "mem/ruby/system/BankedArray.hh"
#include "mem/ruby/system/LRUPolicy.hh"
#include "mem/ruby/system/PseudoLRUPolicy.hh"
#include "params/RubyCache.hh"
@@ -125,6 +127,10 @@ class CacheMemory : public SimObject
Stats::Scalar numTagArrayReads;
Stats::Scalar numTagArrayWrites;
+ bool checkResourceAvailable(CacheResourceType res, Address addr);
+
+ Stats::Scalar numTagArrayStalls;
+ Stats::Scalar numDataArrayStalls;
private:
// convert a Address to its location in the cache
Index addressToCacheSet(const Address& address) const;
@@ -155,12 +161,16 @@ class CacheMemory : public SimObject
CacheProfiler* m_profiler_ptr;
+ BankedArray dataArray;
+ BankedArray tagArray;
+
int m_cache_size;
std::string m_policy;
int m_cache_num_sets;
int m_cache_num_set_bits;
int m_cache_assoc;
int m_start_index_bit;
+ bool m_resource_stalls;
};
#endif // __MEM_RUBY_SYSTEM_CACHEMEMORY_HH__
diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript
index baa877b39..6bb6d2707 100644
--- a/src/mem/ruby/system/SConscript
+++ b/src/mem/ruby/system/SConscript
@@ -55,3 +55,4 @@ Source('RubyPortProxy.cc')
Source('Sequencer.cc')
Source('System.cc')
Source('TimerTable.cc')
+Source('BankedArray.cc')
diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py
index 230eb1b22..39f3a4b43 100644
--- a/src/mem/slicc/symbols/StateMachine.py
+++ b/src/mem/slicc/symbols/StateMachine.py
@@ -1238,6 +1238,14 @@ if (!%s.areNSlotsAvailable(%s))
''' % (key.code, val)
case_sorter.append(val)
+ # Check all of the request_types for resource constraints
+ for request_type in request_types:
+ val = '''
+if (!checkResourceAvailable(%s_RequestType_%s, addr)) {
+ return TransitionResult_ResourceStall;
+}
+''' % (self.ident, request_type.ident)
+ case_sorter.append(val)
# Emit the code sequences in a sorted order. This makes the
# output deterministic (without this the output order can vary