From 6d22db4eaa6cfb73b4a393c9f180867cebe2328f Mon Sep 17 00:00:00 2001 From: Brad Beckmann Date: Sun, 21 Mar 2010 21:22:21 -0700 Subject: [PATCH] ruby: Ruby support for LLSC --- src/mem/ruby/system/CacheMemory.cc | 17 ++++++++- src/mem/ruby/system/RubyPort.cc | 58 ++++++++++++++++++++++++------ src/mem/ruby/system/SConscript | 2 ++ src/mem/ruby/system/Sequencer.cc | 45 ++++++++++++++++++----- 4 files changed, 102 insertions(+), 20 deletions(-) diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc index 110dce2d0..35625245a 100644 --- a/src/mem/ruby/system/CacheMemory.cc +++ b/src/mem/ruby/system/CacheMemory.cc @@ -252,6 +252,7 @@ void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) m_cache[cacheSet][i] = entry; // Init entry m_cache[cacheSet][i]->m_Address = address; m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid; + DPRINTF(RubyCache, "Allocate clearing lock for addr: %llx\n", address); m_locked[cacheSet][i] = -1; m_tag_index[address] = i; @@ -273,6 +274,7 @@ void CacheMemory::deallocate(const Address& address) if (location != -1){ delete m_cache[cacheSet][location]; m_cache[cacheSet][location] = NULL; + DPRINTF(RubyCache, "Deallocate clearing lock for addr: %llx\n", address); m_locked[cacheSet][location] = -1; m_tag_index.erase(address); } @@ -320,7 +322,10 @@ void CacheMemory::changePermission(const Address& address, AccessPermission new_ lookup(address).m_Permission = new_perm; Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); - m_locked[cacheSet][loc] = -1; + if (new_perm != AccessPermission_Read_Write) { + DPRINTF(RubyCache, "Permission clearing lock for addr: %llx\n", address); + m_locked[cacheSet][loc] = -1; + } assert(getPermission(address) == new_perm); } @@ -422,6 +427,10 @@ void CacheMemory::setMemoryValue(const Address& addr, char* value, void CacheMemory::setLocked(const Address& address, int context) { + DPRINTF(RubyCache, + "Setting Lock for addr: %llx to %d\n", + address, + context); assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); @@ -432,6 +441,7 @@ CacheMemory::setLocked(const Address& address, int context) void CacheMemory::clearLocked(const Address& address) { + DPRINTF(RubyCache, "Clear Lock for addr: %llx\n", address); assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); @@ -446,6 +456,11 @@ CacheMemory::isLocked(const Address& address, int context) Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); assert(loc != -1); + DPRINTF(RubyCache, + "Testing Lock for addr: %llx cur %d con %d\n", + address, + m_locked[cacheSet][loc], + context); return m_locked[cacheSet][loc] == context; } diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index 07a06bd07..314f551d1 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -210,18 +210,33 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt) pc = pkt->req->getPC(); } - if (pkt->isRead()) { - if (pkt->req->isInstFetch()) { - type = RubyRequestType_IFETCH; + if (pkt->isLLSC()) { + if (pkt->isWrite()) { + DPRINTF(MemoryAccess, "Issuing SC\n"); + type = RubyRequestType_Locked_Write; } else { - type = RubyRequestType_LD; + DPRINTF(MemoryAccess, "Issuing LL\n"); + assert(pkt->isRead()); + type = RubyRequestType_Locked_Read; } - } else if (pkt->isWrite()) { - type = RubyRequestType_ST; - } else if (pkt->isReadWrite()) { - type = RubyRequestType_RMW_Write; } else { - panic("Unsupported ruby packet type\n"); + if (pkt->isRead()) { + if (pkt->req->isInstFetch()) { + type = RubyRequestType_IFETCH; + } else { + type = RubyRequestType_LD; + } + } else if (pkt->isWrite()) { + type = RubyRequestType_ST; + } else if (pkt->isReadWrite()) { + // + // Fix me. Just because the packet is a read/write request does not + // necessary mean it is a read-modify-write atomic operation. + // + type = RubyRequestType_RMW_Write; + } else { + panic("Unsupported ruby packet type\n"); + } } RubyRequest ruby_request(pkt->getAddr(), @@ -234,10 +249,31 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt) // Submit the ruby request RequestStatus requestStatus = ruby_port->makeRequest(ruby_request); - if (requestStatus == RequestStatus_Issued) { + + // + // If the request successfully issued or the SC request completed because + // exclusive permission was lost, then we should return true. + // Otherwise, we need to delete the senderStatus we just created and return + // false. + // + if ((requestStatus == RequestStatus_Issued) || + (requestStatus == RequestStatus_LlscFailed)) { + + // + // The communicate to M5 whether the SC command succeeded by seting the + // packet's extra data. + // + if (pkt->isLLSC() && pkt->isWrite()) { + if (requestStatus == RequestStatus_LlscFailed) { + DPRINTF(MemoryAccess, "SC failed and request completed\n"); + pkt->req->setExtraData(0); + } else { + pkt->req->setExtraData(1); + } + } return true; } - + DPRINTF(MemoryAccess, "Request for address #x did not issue because %s\n", pkt->getAddr(), diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript index bd721e83d..715c9fb86 100644 --- a/src/mem/ruby/system/SConscript +++ b/src/mem/ruby/system/SConscript @@ -49,3 +49,5 @@ Source('RubyPort.cc') Source('Sequencer.cc', Werror=False) Source('System.cc') Source('TimerTable.cc') + +TraceFlag('RubyCache') diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc index b471a4b8b..d6dba08f9 100644 --- a/src/mem/ruby/system/Sequencer.cc +++ b/src/mem/ruby/system/Sequencer.cc @@ -334,11 +334,24 @@ void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) { if (ruby_request.data != NULL) { if ((type == RubyRequestType_LD) || (type == RubyRequestType_IFETCH) || - (type == RubyRequestType_RMW_Read)) { - memcpy(ruby_request.data, data.getData(request_address.getOffset(), ruby_request.len), ruby_request.len); + (type == RubyRequestType_RMW_Read) || + (type == RubyRequestType_Locked_Read)) { + + memcpy(ruby_request.data, + data.getData(request_address.getOffset(), ruby_request.len), + ruby_request.len); + } else { - data.setData(ruby_request.data, request_address.getOffset(), ruby_request.len); + + data.setData(ruby_request.data, + request_address.getOffset(), + ruby_request.len); + } + } else { + DPRINTF(MemoryAccess, + "WARNING. Data not transfered from Ruby to M5 for type %s\n", + RubyRequestType_to_string(type)); } // @@ -403,11 +416,27 @@ RequestStatus Sequencer::makeRequest(const RubyRequest & request) bool found = insertRequest(srequest); if (!found) { if (request.type == RubyRequestType_Locked_Write) { - // NOTE: it is OK to check the locked flag here as the mandatory queue will be checked first - // ensuring that nothing comes between checking the flag and servicing the store - if (!m_dataCache_ptr->isLocked(line_address(Address(request.paddr)), m_version)) { - return RequestStatus_LlscFailed; - } + // + // NOTE: it is OK to check the locked flag here as the mandatory queue + // will be checked first ensuring that nothing comes between checking + // the flag and servicing the store. + // + if (!m_dataCache_ptr->isLocked(line_address(Address(request.paddr)), + m_version)) { + removeRequest(srequest); + if (Debug::getProtocolTrace()) { + + g_system_ptr->getProfiler()->profileTransition("Seq", + m_version, + Address(request.paddr), + "", + "SC Fail", + "", + RubyRequestType_to_string(request.type)); + + } + return RequestStatus_LlscFailed; + } else { m_dataCache_ptr->clearLocked(line_address(Address(request.paddr))); } -- 2.30.2