summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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