summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLisa Hsu <Lisa.Hsu@amd.com>2011-09-01 11:41:44 -0700
committerLisa Hsu <Lisa.Hsu@amd.com>2011-09-01 11:41:44 -0700
commitae12ae30239a4d62bdb7e88f0d9f7be613fa1005 (patch)
treec94eca59c43aa6e8c0f91f094a4df7a66b1624c5
parentebda5c14a57d4c140e664b6f9c31dae9a94552aa (diff)
downloadgem5-ae12ae30239a4d62bdb7e88f0d9f7be613fa1005.tar.xz
Functional Accesses: Update states to support Broadcast/Snooping protocols.
In the current implementation of Functional Accesses, it's very hard to implement broadcast or snooping protocols where the memory has no idea if it has exclusive access to a cache block or not. Without this knowledge, making sure the RW vs. RO permissions are right are next to impossible. So we add a new state called Backing_Store to enable the conveyance that this is the backup storage for a block, so that it can be written if it is the only possibly RW block in the system, or written even if there is another RW block in the system, without causing problems. Also, a small change to actually set the m_name field for each Controller so that debugging can be easier. Now you can access a controller's name just by controller->getName().
-rw-r--r--src/mem/protocol/RubySlicc_Exports.sm8
-rw-r--r--src/mem/ruby/system/RubyPort.cc162
-rw-r--r--src/mem/slicc/symbols/StateMachine.py1
3 files changed, 129 insertions, 42 deletions
diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm
index e8616521a..ca80047f7 100644
--- a/src/mem/protocol/RubySlicc_Exports.sm
+++ b/src/mem/protocol/RubySlicc_Exports.sm
@@ -63,6 +63,14 @@ enumeration(AccessPermission, desc="...", default="AccessPermission_NotPresent")
// writes should update the block because a dataless PUT request may
// revalidate the block's data.
Maybe_Stale, desc="block can be stale or revalidated by a dataless PUT";
+ // In Broadcast/Snoop protocols, memory has no idea if it is exclusive owner
+ // or not of a block, making it hard to make the logic of having only one
+ // read_write block in the system impossible. This is to allow the memory to
+ // say, "I have the block" and for the RubyPort logic to know that this is a
+ // last-resort block if there are no writable copies in the caching hierarchy.
+ // This is not supposed to be used in directory or token protocols where
+ // memory/NB has an idea of what is going on in the whole system.
+ Backing_Store, desc="for memory in Broadcast/Snoop protocols";
// Invalid data
Invalid, desc="block is in an Invalid base state";
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 179b0f4a1..c2661bcf2 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -300,35 +300,97 @@ RubyPort::M5Port::doFunctionalRead(PacketPtr pkt)
Address line_address(address);
line_address.makeLineAddress();
- AccessPermission accessPerm = AccessPermission_NotPresent;
+ AccessPermission access_perm = AccessPermission_NotPresent;
int num_controllers = ruby_system->m_abs_cntrl_vec.size();
- // In this loop, we try to figure which controller has a read only or
- // a read write copy of the given address. Any valid copy would suffice
- // for a functional read.
-
DPRINTF(RubyPort, "Functional Read request for %s\n",address);
- for(int i = 0;i < num_controllers;++i)
+
+ unsigned int num_ro = 0;
+ unsigned int num_rw = 0;
+ unsigned int num_busy = 0;
+ unsigned int num_backing_store = 0;
+ unsigned int num_invalid = 0;
+
+ // In this loop we count the number of controllers that have the given
+ // address in read only, read write and busy states.
+ for (int i = 0; i < num_controllers; ++i) {
+ access_perm = ruby_system->m_abs_cntrl_vec[i]->
+ getAccessPermission(line_address);
+ if (access_perm == AccessPermission_Read_Only)
+ num_ro++;
+ else if (access_perm == AccessPermission_Read_Write)
+ num_rw++;
+ else if (access_perm == AccessPermission_Busy)
+ num_busy++;
+ else if (access_perm == AccessPermission_Backing_Store)
+ // See RubySlicc_Exports.sm for details, but Backing_Store is meant
+ // to represent blocks in memory *for Broadcast/Snooping protocols*,
+ // where memory has no idea whether it has an exclusive copy of data
+ // or not.
+ num_backing_store++;
+ else if (access_perm == AccessPermission_Invalid ||
+ access_perm == AccessPermission_NotPresent)
+ num_invalid++;
+ }
+ assert(num_rw <= 1);
+
+ uint8* data = pkt->getPtr<uint8_t>(true);
+ unsigned int size_in_bytes = pkt->getSize();
+ unsigned startByte = address.getAddress() - line_address.getAddress();
+
+ // This if case is meant to capture what happens in a Broadcast/Snoop
+ // protocol where the block does not exist in the cache hierarchy. You
+ // only want to read from the Backing_Store memory if there is no copy in
+ // the cache hierarchy, otherwise you want to try to read the RO or RW
+ // copies existing in the cache hierarchy (covered by the else statement).
+ // The reason is because the Backing_Store memory could easily be stale, if
+ // there are copies floating around the cache hierarchy, so you want to read
+ // it only if it's not in the cache hierarchy at all.
+ if (num_invalid == (num_controllers - 1) &&
+ num_backing_store == 1)
{
- accessPerm = ruby_system->m_abs_cntrl_vec[i]
- ->getAccessPermission(line_address);
- if(accessPerm == AccessPermission_Read_Only ||
- accessPerm == AccessPermission_Read_Write)
- {
- unsigned startByte = address.getAddress() - line_address.getAddress();
-
- uint8* data = pkt->getPtr<uint8_t>(true);
- unsigned int size_in_bytes = pkt->getSize();
- DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
+ DPRINTF(RubyPort, "only copy in Backing_Store memory, read from it\n");
+ for (int i = 0; i < num_controllers; ++i) {
+ access_perm = ruby_system->m_abs_cntrl_vec[i]
+ ->getAccessPermission(line_address);
+ if (access_perm == AccessPermission_Backing_Store) {
+ DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
->getDataBlock(line_address);
- DPRINTF(RubyPort, "reading from %s block %s\n",
- ruby_system->m_abs_cntrl_vec[i]->name(), block);
- for (unsigned i = 0; i < size_in_bytes; ++i)
+ DPRINTF(RubyPort, "reading from %s block %s\n",
+ ruby_system->m_abs_cntrl_vec[i]->name(), block);
+ for (unsigned i = 0; i < size_in_bytes; ++i) {
+ data[i] = block.getByte(i + startByte);
+ }
+ return true;
+ }
+ }
+ } else {
+ // In Broadcast/Snoop protocols, this covers if you know the block
+ // exists somewhere in the caching hierarchy, then you want to read any
+ // valid RO or RW block. In directory protocols, same thing, you want
+ // to read any valid readable copy of the block.
+ DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n",
+ num_busy, num_ro, num_rw);
+ // In this loop, we try to figure which controller has a read only or
+ // a read write copy of the given address. Any valid copy would suffice
+ // for a functional read.
+ for(int i = 0;i < num_controllers;++i) {
+ access_perm = ruby_system->m_abs_cntrl_vec[i]
+ ->getAccessPermission(line_address);
+ if(access_perm == AccessPermission_Read_Only ||
+ access_perm == AccessPermission_Read_Write)
{
- data[i] = block.getByte(i + startByte);
+ DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
+ ->getDataBlock(line_address);
+
+ DPRINTF(RubyPort, "reading from %s block %s\n",
+ ruby_system->m_abs_cntrl_vec[i]->name(), block);
+ for (unsigned i = 0; i < size_in_bytes; ++i) {
+ data[i] = block.getByte(i + startByte);
+ }
+ return true;
}
- return true;
}
}
return false;
@@ -339,7 +401,7 @@ RubyPort::M5Port::doFunctionalWrite(PacketPtr pkt)
{
Address addr(pkt->getAddr());
Address line_addr = line_address(addr);
- AccessPermission accessPerm = AccessPermission_NotPresent;
+ AccessPermission access_perm = AccessPermission_NotPresent;
int num_controllers = ruby_system->m_abs_cntrl_vec.size();
DPRINTF(RubyPort, "Functional Write request for %s\n",addr);
@@ -347,47 +409,63 @@ RubyPort::M5Port::doFunctionalWrite(PacketPtr pkt)
unsigned int num_ro = 0;
unsigned int num_rw = 0;
unsigned int num_busy = 0;
+ unsigned int num_backing_store = 0;
+ unsigned int num_invalid = 0;
// In this loop we count the number of controllers that have the given
// address in read only, read write and busy states.
- for(int i = 0;i < num_controllers;++i)
- {
- accessPerm = ruby_system->m_abs_cntrl_vec[i]->
+ for(int i = 0;i < num_controllers;++i) {
+ access_perm = ruby_system->m_abs_cntrl_vec[i]->
getAccessPermission(line_addr);
- if(accessPerm == AccessPermission_Read_Only) num_ro++;
- else if(accessPerm == AccessPermission_Read_Write) num_rw++;
- else if(accessPerm == AccessPermission_Busy) num_busy++;
+ if (access_perm == AccessPermission_Read_Only)
+ num_ro++;
+ else if (access_perm == AccessPermission_Read_Write)
+ num_rw++;
+ else if (access_perm == AccessPermission_Busy)
+ num_busy++;
+ else if (access_perm == AccessPermission_Backing_Store)
+ // See RubySlicc_Exports.sm for details, but Backing_Store is meant
+ // to represent blocks in memory *for Broadcast/Snooping protocols*,
+ // where memory has no idea whether it has an exclusive copy of data
+ // or not.
+ num_backing_store++;
+ else if (access_perm == AccessPermission_Invalid ||
+ access_perm == AccessPermission_NotPresent)
+ num_invalid++;
}
// If the number of read write copies is more than 1, then there is bug in
// coherence protocol. Otherwise, if all copies are in stable states, i.e.
// num_busy == 0, we update all the copies. If there is at least one copy
// in busy state, then we check if there is read write copy. If yes, then
- // also we let the access go through.
+ // also we let the access go through. Or, if there is no copy in the cache
+ // hierarchy at all, we still want to do the write to the memory
+ // (Backing_Store) instead of failing.
DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n",
num_busy, num_ro, num_rw);
assert(num_rw <= 1);
- if((num_busy == 0 && num_ro > 0) || num_rw == 1)
- {
- uint8* data = pkt->getPtr<uint8_t>(true);
- unsigned int size_in_bytes = pkt->getSize();
- unsigned startByte = addr.getAddress() - line_addr.getAddress();
- for(int i = 0; i < num_controllers;++i)
- {
- accessPerm = ruby_system->m_abs_cntrl_vec[i]->
+ uint8* data = pkt->getPtr<uint8_t>(true);
+ unsigned int size_in_bytes = pkt->getSize();
+ unsigned startByte = addr.getAddress() - line_addr.getAddress();
+
+ if ((num_busy == 0 && num_ro > 0) || num_rw == 1 ||
+ (num_invalid == (num_controllers - 1) && num_backing_store == 1))
+ {
+ for(int i = 0; i < num_controllers;++i) {
+ access_perm = ruby_system->m_abs_cntrl_vec[i]->
getAccessPermission(line_addr);
- if(accessPerm == AccessPermission_Read_Only ||
- accessPerm == AccessPermission_Read_Write||
- accessPerm == AccessPermission_Maybe_Stale)
+ if(access_perm == AccessPermission_Read_Only ||
+ access_perm == AccessPermission_Read_Write||
+ access_perm == AccessPermission_Maybe_Stale ||
+ access_perm == AccessPermission_Backing_Store)
{
DataBlock& block = ruby_system->m_abs_cntrl_vec[i]
->getDataBlock(line_addr);
DPRINTF(RubyPort, "%s\n",block);
- for (unsigned i = 0; i < size_in_bytes; ++i)
- {
+ for (unsigned i = 0; i < size_in_bytes; ++i) {
block.setByte(i + startByte, data[i]);
}
DPRINTF(RubyPort, "%s\n",block);
diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py
index 42249ab7a..fbd090d49 100644
--- a/src/mem/slicc/symbols/StateMachine.py
+++ b/src/mem/slicc/symbols/StateMachine.py
@@ -456,6 +456,7 @@ $c_ident::$c_ident(const Params *p)
m_recycle_latency = p->recycle_latency;
m_number_of_TBEs = p->number_of_TBEs;
m_is_blocking = false;
+ m_name = "${ident}";
''')
#
# max_port_rank is used to size vectors and thus should be one plus the