ruby: Ruby support for LLSC
This commit is contained in:
@@ -252,6 +252,7 @@ void CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
|
|||||||
m_cache[cacheSet][i] = entry; // Init entry
|
m_cache[cacheSet][i] = entry; // Init entry
|
||||||
m_cache[cacheSet][i]->m_Address = address;
|
m_cache[cacheSet][i]->m_Address = address;
|
||||||
m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
|
m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
|
||||||
|
DPRINTF(RubyCache, "Allocate clearing lock for addr: %llx\n", address);
|
||||||
m_locked[cacheSet][i] = -1;
|
m_locked[cacheSet][i] = -1;
|
||||||
m_tag_index[address] = i;
|
m_tag_index[address] = i;
|
||||||
|
|
||||||
@@ -273,6 +274,7 @@ void CacheMemory::deallocate(const Address& address)
|
|||||||
if (location != -1){
|
if (location != -1){
|
||||||
delete m_cache[cacheSet][location];
|
delete m_cache[cacheSet][location];
|
||||||
m_cache[cacheSet][location] = NULL;
|
m_cache[cacheSet][location] = NULL;
|
||||||
|
DPRINTF(RubyCache, "Deallocate clearing lock for addr: %llx\n", address);
|
||||||
m_locked[cacheSet][location] = -1;
|
m_locked[cacheSet][location] = -1;
|
||||||
m_tag_index.erase(address);
|
m_tag_index.erase(address);
|
||||||
}
|
}
|
||||||
@@ -320,7 +322,10 @@ void CacheMemory::changePermission(const Address& address, AccessPermission new_
|
|||||||
lookup(address).m_Permission = new_perm;
|
lookup(address).m_Permission = new_perm;
|
||||||
Index cacheSet = addressToCacheSet(address);
|
Index cacheSet = addressToCacheSet(address);
|
||||||
int loc = findTagInSet(cacheSet, 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);
|
assert(getPermission(address) == new_perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,6 +427,10 @@ void CacheMemory::setMemoryValue(const Address& addr, char* value,
|
|||||||
void
|
void
|
||||||
CacheMemory::setLocked(const Address& address, int context)
|
CacheMemory::setLocked(const Address& address, int context)
|
||||||
{
|
{
|
||||||
|
DPRINTF(RubyCache,
|
||||||
|
"Setting Lock for addr: %llx to %d\n",
|
||||||
|
address,
|
||||||
|
context);
|
||||||
assert(address == line_address(address));
|
assert(address == line_address(address));
|
||||||
Index cacheSet = addressToCacheSet(address);
|
Index cacheSet = addressToCacheSet(address);
|
||||||
int loc = findTagInSet(cacheSet, address);
|
int loc = findTagInSet(cacheSet, address);
|
||||||
@@ -432,6 +441,7 @@ CacheMemory::setLocked(const Address& address, int context)
|
|||||||
void
|
void
|
||||||
CacheMemory::clearLocked(const Address& address)
|
CacheMemory::clearLocked(const Address& address)
|
||||||
{
|
{
|
||||||
|
DPRINTF(RubyCache, "Clear Lock for addr: %llx\n", address);
|
||||||
assert(address == line_address(address));
|
assert(address == line_address(address));
|
||||||
Index cacheSet = addressToCacheSet(address);
|
Index cacheSet = addressToCacheSet(address);
|
||||||
int loc = findTagInSet(cacheSet, address);
|
int loc = findTagInSet(cacheSet, address);
|
||||||
@@ -446,6 +456,11 @@ CacheMemory::isLocked(const Address& address, int context)
|
|||||||
Index cacheSet = addressToCacheSet(address);
|
Index cacheSet = addressToCacheSet(address);
|
||||||
int loc = findTagInSet(cacheSet, address);
|
int loc = findTagInSet(cacheSet, address);
|
||||||
assert(loc != -1);
|
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;
|
return m_locked[cacheSet][loc] == context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -210,18 +210,33 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
|
|||||||
pc = pkt->req->getPC();
|
pc = pkt->req->getPC();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt->isRead()) {
|
if (pkt->isLLSC()) {
|
||||||
if (pkt->req->isInstFetch()) {
|
if (pkt->isWrite()) {
|
||||||
type = RubyRequestType_IFETCH;
|
DPRINTF(MemoryAccess, "Issuing SC\n");
|
||||||
|
type = RubyRequestType_Locked_Write;
|
||||||
} else {
|
} 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 {
|
} 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(),
|
RubyRequest ruby_request(pkt->getAddr(),
|
||||||
@@ -234,10 +249,31 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt)
|
|||||||
|
|
||||||
// Submit the ruby request
|
// Submit the ruby request
|
||||||
RequestStatus requestStatus = ruby_port->makeRequest(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINTF(MemoryAccess,
|
DPRINTF(MemoryAccess,
|
||||||
"Request for address #x did not issue because %s\n",
|
"Request for address #x did not issue because %s\n",
|
||||||
pkt->getAddr(),
|
pkt->getAddr(),
|
||||||
|
|||||||
@@ -49,3 +49,5 @@ Source('RubyPort.cc')
|
|||||||
Source('Sequencer.cc', Werror=False)
|
Source('Sequencer.cc', Werror=False)
|
||||||
Source('System.cc')
|
Source('System.cc')
|
||||||
Source('TimerTable.cc')
|
Source('TimerTable.cc')
|
||||||
|
|
||||||
|
TraceFlag('RubyCache')
|
||||||
|
|||||||
@@ -334,11 +334,24 @@ void Sequencer::hitCallback(SequencerRequest* srequest, DataBlock& data) {
|
|||||||
if (ruby_request.data != NULL) {
|
if (ruby_request.data != NULL) {
|
||||||
if ((type == RubyRequestType_LD) ||
|
if ((type == RubyRequestType_LD) ||
|
||||||
(type == RubyRequestType_IFETCH) ||
|
(type == RubyRequestType_IFETCH) ||
|
||||||
(type == RubyRequestType_RMW_Read)) {
|
(type == RubyRequestType_RMW_Read) ||
|
||||||
memcpy(ruby_request.data, data.getData(request_address.getOffset(), ruby_request.len), ruby_request.len);
|
(type == RubyRequestType_Locked_Read)) {
|
||||||
|
|
||||||
|
memcpy(ruby_request.data,
|
||||||
|
data.getData(request_address.getOffset(), ruby_request.len),
|
||||||
|
ruby_request.len);
|
||||||
|
|
||||||
} else {
|
} 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);
|
bool found = insertRequest(srequest);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (request.type == RubyRequestType_Locked_Write) {
|
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
|
// NOTE: it is OK to check the locked flag here as the mandatory queue
|
||||||
if (!m_dataCache_ptr->isLocked(line_address(Address(request.paddr)), m_version)) {
|
// will be checked first ensuring that nothing comes between checking
|
||||||
return RequestStatus_LlscFailed;
|
// 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 {
|
else {
|
||||||
m_dataCache_ptr->clearLocked(line_address(Address(request.paddr)));
|
m_dataCache_ptr->clearLocked(line_address(Address(request.paddr)));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user