summaryrefslogtreecommitdiff
path: root/src/mem/ruby/system/RubyPort.cc
diff options
context:
space:
mode:
authorBrad Beckmann ext:(%2C%20Nilay%20Vaish%20%3Cnilay%40cs.wisc.edu%3E) <Brad.Beckmann@amd.com>2011-06-30 19:49:26 -0500
committerBrad Beckmann ext:(%2C%20Nilay%20Vaish%20%3Cnilay%40cs.wisc.edu%3E) <Brad.Beckmann@amd.com>2011-06-30 19:49:26 -0500
commitc86f849d5a1da1fc77f2fca43b82cb6760f68bc9 (patch)
treef192cbc73d86ee4e15e752f6ed174e4ce3425c9e /src/mem/ruby/system/RubyPort.cc
parentf4cfd65d2982f0f97304ef05083b40f3346a496f (diff)
downloadgem5-c86f849d5a1da1fc77f2fca43b82cb6760f68bc9.tar.xz
Ruby: Add support for functional accesses
This patch rpovides functional access support in Ruby. Currently only the M5Port of RubyPort supports functional accesses. The support for functional through the PioPort will be added as a separate patch.
Diffstat (limited to 'src/mem/ruby/system/RubyPort.cc')
-rw-r--r--src/mem/ruby/system/RubyPort.cc175
1 files changed, 170 insertions, 5 deletions
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 40f893257..662f971f2 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -31,8 +31,8 @@
#include "arch/x86/insts/microldstop.hh"
#endif // X86_ISA
#include "cpu/testers/rubytest/RubyTester.hh"
-#include "debug/MemoryAccess.hh"
#include "debug/Ruby.hh"
+#include "mem/protocol/AccessPermission.hh"
#include "mem/ruby/slicc_interface/AbstractController.hh"
#include "mem/ruby/system/RubyPort.hh"
#include "mem/physical.hh"
@@ -54,6 +54,8 @@ RubyPort::RubyPort(const Params *p)
m_usingRubyTester = p->using_ruby_tester;
access_phys_mem = p->access_phys_mem;
+
+ ruby_system = p->ruby_system;
}
void
@@ -68,7 +70,7 @@ RubyPort::getPort(const std::string &if_name, int idx)
{
if (if_name == "port") {
return new M5Port(csprintf("%s-port%d", name(), idx), this,
- access_phys_mem);
+ ruby_system, access_phys_mem);
}
if (if_name == "pio_port") {
@@ -85,7 +87,7 @@ RubyPort::getPort(const std::string &if_name, int idx)
assert (physMemPort == NULL);
physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this,
- access_phys_mem);
+ ruby_system, access_phys_mem);
return physMemPort;
}
@@ -109,12 +111,13 @@ RubyPort::PioPort::PioPort(const std::string &_name,
ruby_port = _port;
}
-RubyPort::M5Port::M5Port(const std::string &_name,
- RubyPort *_port, bool _access_phys_mem)
+RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port,
+ RubySystem *_system, bool _access_phys_mem)
: SimpleTimingPort(_name, _port)
{
DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name);
ruby_port = _port;
+ ruby_system = _system;
_onRetryList = false;
access_phys_mem = _access_phys_mem;
}
@@ -289,6 +292,168 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
return false;
}
+bool
+RubyPort::M5Port::doFunctionalRead(PacketPtr pkt)
+{
+ Address address(pkt->getAddr());
+ Address line_address(address);
+ line_address.makeLineAddress();
+
+ AccessPermission accessPerm = 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)
+ {
+ 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]
+ ->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 false;
+}
+
+bool
+RubyPort::M5Port::doFunctionalWrite(PacketPtr pkt)
+{
+ Address addr(pkt->getAddr());
+ Address line_addr = line_address(addr);
+ AccessPermission accessPerm = AccessPermission_NotPresent;
+ int num_controllers = ruby_system->m_abs_cntrl_vec.size();
+
+ DPRINTF(RubyPort, "Functional Write request for %s\n",addr);
+
+ unsigned int num_ro = 0;
+ unsigned int num_rw = 0;
+ unsigned int num_busy = 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]->
+ 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 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.
+
+ 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]->
+ getAccessPermission(line_addr);
+ if(accessPerm == AccessPermission_Read_Only ||
+ accessPerm == AccessPermission_Read_Write||
+ accessPerm == AccessPermission_Maybe_Stale)
+ {
+ 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)
+ {
+ block.setByte(i + startByte, data[i]);
+ }
+ DPRINTF(RubyPort, "%s\n",block);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+RubyPort::M5Port::recvFunctional(PacketPtr pkt)
+{
+ DPRINTF(RubyPort, "Functional access caught for address %#x\n",
+ pkt->getAddr());
+
+ // Check for pio requests and directly send them to the dedicated
+ // pio port.
+ if (!isPhysMemAddress(pkt->getAddr())) {
+ assert(ruby_port->pio_port != NULL);
+ DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n",
+ pkt->getAddr());
+ panic("RubyPort::PioPort::recvFunctional() not implemented!\n");
+ }
+
+ assert(pkt->getAddr() + pkt->getSize() <=
+ line_address(Address(pkt->getAddr())).getAddress() +
+ RubySystem::getBlockSizeBytes());
+
+ bool accessSucceeded = false;
+ bool needsResponse = pkt->needsResponse();
+
+ // Do the functional access on ruby memory
+ if (pkt->isRead()) {
+ accessSucceeded = doFunctionalRead(pkt);
+ } else if (pkt->isWrite()) {
+ accessSucceeded = doFunctionalWrite(pkt);
+ } else {
+ panic("RubyPort: unsupported functional command %s\n",
+ pkt->cmdString());
+ }
+
+ // Unless the requester explicitly said otherwise, generate an error if
+ // the functional request failed
+ if (!accessSucceeded && !pkt->suppressFuncError()) {
+ fatal("Ruby functional %s failed for address %#x\n",
+ pkt->isWrite() ? "write" : "read", pkt->getAddr());
+ }
+
+ if (access_phys_mem) {
+ // The attached physmem contains the official version of data.
+ // The following command performs the real functional access.
+ // This line should be removed once Ruby supplies the official version
+ // of data.
+ ruby_port->physMemPort->sendFunctional(pkt);
+ }
+
+ // turn packet around to go back to requester if response expected
+ if (needsResponse) {
+ pkt->setFunctionalResponseStatus(accessSucceeded);
+ DPRINTF(RubyPort, "Sending packet back over port\n");
+ sendFunctional(pkt);
+ }
+ DPRINTF(RubyPort, "Functional access %s!\n",
+ accessSucceeded ? "successful":"failed");
+}
+
void
RubyPort::ruby_hit_callback(PacketPtr pkt)
{