diff -r 4a6c166f61f7 -r 8232d7b273e5 src/mem/protocol/RubySlicc_Exports.sm --- a/src/mem/protocol/RubySlicc_Exports.sm Tue Jul 26 12:20:22 2011 -0500 +++ b/src/mem/protocol/RubySlicc_Exports.sm Mon Aug 15 15:27:34 2011 -0700 @@ -63,6 +63,14 @@ // 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 -r 4a6c166f61f7 -r 8232d7b273e5 src/mem/ruby/system/RubyPort.cc --- a/src/mem/ruby/system/RubyPort.cc Tue Jul 26 12:20:22 2011 -0500 +++ b/src/mem/ruby/system/RubyPort.cc Mon Aug 15 15:27:34 2011 -0700 @@ -299,35 +299,86 @@ 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); - 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_memory = 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) + num_memory++; + else if (access_perm == AccessPermission_Invalid || + access_perm == AccessPermission_NotPresent) + num_invalid++; + } + assert(num_rw <= 1); + + uint8* data = pkt->getPtr(true); + unsigned int size_in_bytes = pkt->getSize(); + unsigned startByte = address.getAddress() - line_address.getAddress(); + + // the only copy is the one in memory, read that one + if (num_invalid == (num_controllers - 1) && + num_memory == 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(true); - unsigned int size_in_bytes = pkt->getSize(); - DataBlock& block = ruby_system->m_abs_cntrl_vec[i] + DPRINTF(RubyPort, "only copy is in memory, read from there\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 { + // exists in cache hierarchy, get it from a readable copy in there + // Don't want to collapse the two if/else's because it's possible for + // the memory to be stale, and you only want to read it as a last resort + // if it turns out it doesn't exist in the caching hierarchy. + 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; @@ -338,7 +389,7 @@ { 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); @@ -346,47 +397,59 @@ unsigned int num_ro = 0; unsigned int num_rw = 0; unsigned int num_busy = 0; + unsigned int num_memory = 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) + num_memory++; + 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(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_memory == 1)) { - uint8* data = pkt->getPtr(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]-> + 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 -r 4a6c166f61f7 -r 8232d7b273e5 src/mem/slicc/symbols/StateMachine.py --- a/src/mem/slicc/symbols/StateMachine.py Tue Jul 26 12:20:22 2011 -0500 +++ b/src/mem/slicc/symbols/StateMachine.py Mon Aug 15 15:27:34 2011 -0700 @@ -459,6 +459,7 @@ 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