ruby: improved support for functional accesses

This patch adds support to different entities in the ruby memory system
for more reliable functional read/write accesses. Only the simple network
has been augmented as of now. Later on Garnet will also support functional
accesses.
The patch adds functional access code to all the different types of messages
that protocols can send around. These messages are functionally accessed
by going through the buffers maintained by the network entities.
The patch also rectifies some of the bugs found in coherence protocols while
testing the patch.

With this patch applied, functional writes always succeed. But functional
reads can still fail.
This commit is contained in:
Nilay Vaish 2012-10-15 17:51:57 -05:00
parent 07ce90f7aa
commit 5ffc165939
45 changed files with 802 additions and 138 deletions

View file

@ -43,7 +43,6 @@ import Ruby
# Get paths we might need. It's expected this file is in m5/configs/example.
config_path = os.path.dirname(os.path.abspath(__file__))
config_root = os.path.dirname(config_path)
m5_root = os.path.dirname(config_root)
parser = optparse.OptionParser()
Options.addCommonOptions(parser)

View file

@ -201,6 +201,11 @@ machine(L1Cache, "MESI Directory L1 Cache CMP")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
TBE tbe := L1_TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
return getCacheEntry(addr).DataBlk;
}

View file

@ -232,6 +232,11 @@ machine(L2Cache, "MESI Directory L2 Cache CMP")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
TBE tbe := L2_TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
return getCacheEntry(addr).DataBlk;
}

View file

@ -170,6 +170,11 @@ machine(Directory, "MESI_CMP_filter_directory protocol")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
return getDirectoryEntry(addr).DataBlk;
}

View file

@ -35,11 +35,9 @@ enumeration(CoherenceRequestType, desc="...") {
GETS, desc="Get Shared";
GET_INSTR, desc="Get Instruction";
INV, desc="INValidate";
PUTX, desc="replacement message";
PUTX, desc="Replacement message";
WB_ACK, desc="Writeback ack";
WB_NACK, desc="Writeback neg. ack";
FWD, desc="Generic FWD";
DMA_READ, desc="DMA Read";
DMA_WRITE, desc="DMA Write";
@ -48,9 +46,9 @@ enumeration(CoherenceRequestType, desc="...") {
// CoherenceResponseType
enumeration(CoherenceResponseType, desc="...") {
MEMORY_ACK, desc="Ack from memory controller";
DATA, desc="Data";
DATA_EXCLUSIVE, desc="Data";
MEMORY_DATA, desc="Data";
DATA, desc="Data block for L1 cache in S state";
DATA_EXCLUSIVE, desc="Data block for L1 cache in M/E state";
MEMORY_DATA, desc="Data block from / to main memory";
ACK, desc="Generic invalidate ack";
WB_ACK, desc="writeback ack";
UNBLOCK, desc="unblock";
@ -70,6 +68,21 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
int Len;
bool Dirty, default="false", desc="Dirty bit";
PrefetchBit Prefetch, desc="Is this a prefetch request";
bool functionalRead(Packet *pkt) {
// Only PUTX messages contains the data block
if (Type == CoherenceRequestType:PUTX) {
return testAndRead(Address, DataBlk, pkt);
}
return false;
}
bool functionalWrite(Packet *pkt) {
// No check on message type required since the protocol should
// read data from those messages that contain the block
return testAndWrite(Address, DataBlk, pkt);
}
}
// ResponseMsg
@ -82,4 +95,22 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
bool Dirty, default="false", desc="Dirty bit";
int AckCount, default="0", desc="number of acks in this message";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
// Valid data block is only present in message with following types
if (Type == CoherenceResponseType:DATA ||
Type == CoherenceResponseType:DATA_EXCLUSIVE ||
Type == CoherenceResponseType:MEMORY_DATA) {
return testAndRead(Address, DataBlk, pkt);
}
return false;
}
bool functionalWrite(Packet *pkt) {
// No check on message type required since the protocol should
// read data from those messages that contain the block
return testAndWrite(Address, DataBlk, pkt);
}
}

View file

@ -168,6 +168,11 @@ machine(L1Cache, "MI Example L1 Cache")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
return getCacheEntry(addr).DataBlk;
}

View file

@ -172,6 +172,11 @@ machine(Directory, "Directory protocol")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
return getDirectoryEntry(addr).DataBlk;
}
@ -506,7 +511,6 @@ machine(Directory, "Directory protocol")
out_msg.OriginalRequestorMachId := in_msg.Requestor;
out_msg.DataBlk := in_msg.DataBlk;
out_msg.MessageSize := in_msg.MessageSize;
//out_msg.Prefetch := in_msg.Prefetch;
DPRINTF(RubySlicc,"%s\n", out_msg);
}
@ -518,12 +522,8 @@ machine(Directory, "Directory protocol")
}
action(w_writeDataToMemoryFromTBE, "\w", desc="Write date to directory memory from TBE") {
//getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk;
assert(is_valid(tbe));
getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk,
addressOffset(tbe.PhysicalAddress),
tbe.Len);
getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk;
}
// TRANSITIONS
@ -633,7 +633,6 @@ machine(Directory, "Directory protocol")
}
transition(M, PUTX, MI) {
l_writeDataToMemory;
c_clearOwner;
v_allocateTBEFromRequestNet;
l_queueMemoryWBRequest;

View file

@ -31,11 +31,9 @@ enumeration(CoherenceRequestType, desc="...") {
GETX, desc="Get eXclusive";
GETS, desc="Get Shared";
PUTX, desc="Put eXclusive";
PUTO, desc="Put Owned";
WB_ACK, desc="Writeback ack";
WB_NACK, desc="Writeback neg. ack";
INV, desc="Invalidation";
FWD, desc="Generic FWD";
}
// CoherenceResponseType
@ -59,6 +57,20 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
NetDest Destination, desc="Multicast destination mask";
DataBlock DataBlk, desc="data for the cache line";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
// Valid data block is only present in PUTX messages
if (Type == CoherenceRequestType:PUTX) {
return testAndRead(Address, DataBlk, pkt);
}
return false;
}
bool functionalWrite(Packet *pkt) {
// No check on message type required since the protocol should read
// data block from only those messages that contain valid data
return testAndWrite(Address, DataBlk, pkt);
}
}
// ResponseMsg (and also unblock requests)
@ -70,6 +82,18 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
DataBlock DataBlk, desc="data for the cache line";
bool Dirty, desc="Is the data dirty (different than memory)?";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
// A check on message type should appear here so that only those
// messages that contain data
return testAndRead(Address, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
// No check on message type required since the protocol should read
// data block from only those messages that contain valid data
return testAndWrite(Address, DataBlk, pkt);
}
}
enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
@ -93,6 +117,14 @@ structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
DataBlock DataBlk, desc="DataBlk attached to this request";
int Len, desc="The length of the request";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
return testAndRead(LineAddress, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(LineAddress, DataBlk, pkt);
}
}
structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
@ -102,4 +134,12 @@ structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
NetDest Destination, desc="Destination";
DataBlock DataBlk, desc="DataBlk attached to this request";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
return testAndRead(LineAddress, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(LineAddress, DataBlk, pkt);
}
}

View file

@ -219,7 +219,17 @@ machine(L1Cache, "Directory protocol")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) {
return cache_entry.DataBlk;
}
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
error("Data block missing!");
}
Event mandatory_request_type_to_event(RubyRequestType type) {

View file

@ -193,7 +193,7 @@ machine(L2Cache, "Token protocol")
// TBE fields
structure(TBE, desc="...") {
Address Address, desc="Physical address for this TBE";
Address address, desc="Physical address for this TBE";
State TBEState, desc="Transient state";
Address PC, desc="Program counter of request";
DataBlock DataBlk, desc="Buffer for the data block";
@ -512,11 +512,6 @@ machine(L2Cache, "Token protocol")
return L2Cache_State_to_permission(cache_entry.CacheState);
}
else if (localDirectory.isTagPresent(addr)) {
DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(localDirectory[addr].DirState));
return L2Cache_State_to_permission(localDirectory[addr].DirState);
}
DPRINTF(RubySlicc, "AccessPermission_NotPresent\n");
return AccessPermission:NotPresent;
}
@ -528,6 +523,11 @@ machine(L2Cache, "Token protocol")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
return getCacheEntry(addr).DataBlk;
}
@ -1451,6 +1451,8 @@ machine(L2Cache, "Token protocol")
peek(responseNetwork_in, ResponseMsg) {
assert(is_valid(cache_entry));
cache_entry.DataBlk := in_msg.DataBlk;
DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
address, cache_entry.DataBlk);
if ((cache_entry.Dirty == false) && in_msg.Dirty) {
cache_entry.Dirty := in_msg.Dirty;
}

View file

@ -473,6 +473,9 @@ machine(Directory, "Directory protocol")
// implementation. We include the data in the "dataless"
// message so we can assert the clean data matches the datablock
// in memory
DPRINTF(RubySlicc, "Address: %s, MsgDataBlock: %s MemoryDataBlock: %s\n",
in_msg.Address, in_msg.DataBlk,
getDirectoryEntry(in_msg.Address).DataBlk);
assert(getDirectoryEntry(in_msg.Address).DataBlk == in_msg.DataBlk);
}
}

View file

@ -71,6 +71,16 @@ enumeration(TriggerType, desc="...") {
structure(TriggerMsg, desc="...", interface="Message") {
Address Address, desc="Physical address for this request";
TriggerType Type, desc="Type of trigger";
bool functionalRead(Packet *pkt) {
// Trigger message does not hold data
return false;
}
bool functionalWrite(Packet *pkt) {
// Trigger message does not hold data
return false;
}
}
// RequestMsg (and also forwarded requests)
@ -86,6 +96,20 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
MessageSizeType MessageSize, desc="size category of the message";
RubyAccessMode AccessMode, desc="user/supervisor access type";
PrefetchBit Prefetch, desc="Is this a prefetch request";
bool functionalRead(Packet *pkt) {
// Read only those messages that contain the data
if (Type == CoherenceRequestType:DMA_READ ||
Type == CoherenceRequestType:DMA_WRITE) {
return testAndRead(Address, DataBlk, pkt);
}
return false;
}
bool functionalWrite(Packet *pkt) {
// No check required since all messages are written
return testAndWrite(Address, DataBlk, pkt);
}
}
// ResponseMsg (and also unblock requests)
@ -99,4 +123,20 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
bool Dirty, desc="Is the data dirty (different than memory)?";
int Acks, desc="How many acks to expect";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
// Read only those messages that contain the data
if (Type == CoherenceResponseType:DATA ||
Type == CoherenceResponseType:DATA_EXCLUSIVE ||
Type == CoherenceResponseType:WRITEBACK_CLEAN_DATA ||
Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) {
return testAndRead(Address, DataBlk, pkt);
}
return false;
}
bool functionalWrite(Packet *pkt) {
// No check required since all messages are written
return testAndWrite(Address, DataBlk, pkt);
}
}

View file

@ -139,7 +139,7 @@ machine(L1Cache, "Token protocol")
// TBE fields
structure(TBE, desc="...") {
Address Address, desc="Physical address for this TBE";
Address address, desc="Physical address for this TBE";
State TBEState, desc="Transient state";
int IssueCount, default="0", desc="The number of times we've issued a request for this line.";
Address PC, desc="Program counter of request";

View file

@ -677,6 +677,7 @@ machine(Directory, "Token protocol")
enqueue(memQueue_out, MemoryMsg, latency="1") {
out_msg.Address := address;
out_msg.Type := MemoryRequestType:MEMORY_WB;
out_msg.DataBlk := getDirectoryEntry(address).DataBlk;
DPRINTF(RubySlicc, "%s\n", out_msg);
}
}

View file

@ -1,4 +1,3 @@
/*
* Copyright (c) 1999-2005 Mark D. Hill and David A. Wood
* All rights reserved.
@ -66,6 +65,16 @@ structure(PersistentMsg, desc="...", interface="NetworkMessage") {
MessageSizeType MessageSize, desc="size category of the message";
RubyAccessMode AccessMode, desc="user/supervisor access type";
PrefetchBit Prefetch, desc="Is this a prefetch request";
bool functionalRead(Packet *pkt) {
// No data in persistent messages
return false;
}
bool functionalWrite(Packet *pkt) {
// No data in persistent messages
return false;
}
}
// RequestMsg
@ -79,6 +88,16 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
MessageSizeType MessageSize, desc="size category of the message";
RubyAccessMode AccessMode, desc="user/supervisor access type";
PrefetchBit Prefetch, desc="Is this a prefetch request";
bool functionalRead(Packet *pkt) {
// No data in request messages
return false;
}
bool functionalWrite(Packet *pkt) {
// No data in request messages
return false;
}
}
// ResponseMsg
@ -91,6 +110,16 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
DataBlock DataBlk, desc="data for the cache line";
bool Dirty, desc="Is the data dirty (different than memory)?";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
// No check being carried out on the message type. Would be added later.
return testAndRead(Address, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
// No check required since all messages are written.
return testAndWrite(Address, DataBlk, pkt);
}
}
enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
@ -114,6 +143,14 @@ structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
DataBlock DataBlk, desc="DataBlk attached to this request";
int Len, desc="The length of the request";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
return false;
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(LineAddress, DataBlk, pkt);
}
}
structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
@ -123,4 +160,12 @@ structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
NetDest Destination, desc="Destination";
DataBlock DataBlk, desc="DataBlk attached to this request";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
return false;
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(LineAddress, DataBlk, pkt);
}
}

View file

@ -198,7 +198,17 @@ machine(L1Cache, "AMD Hammer-like protocol")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getCacheEntry(addr).DataBlk;
Entry cache_entry := getCacheEntry(addr);
if(is_valid(cache_entry)) {
return cache_entry.DataBlk;
}
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
error("Missing data block");
}
Entry getL2CacheEntry(Address address), return_by_pointer="yes" {
@ -879,6 +889,7 @@ machine(L1Cache, "AMD Hammer-like protocol")
tbe.ForwardRequestTime,
tbe.FirstResponseTime);
}
DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk);
cache_entry.Dirty := true;
}

View file

@ -87,7 +87,7 @@ machine(Directory, "AMD Hammer-like protocol")
O_DR_B, AccessPermission:Busy, desc="Owner, Dma Read waiting for cache responses";
WB, AccessPermission:Busy, desc="Blocked on a writeback";
WB_O_W, AccessPermission:Busy, desc="Blocked on memory write, will go to O";
WB_E_W, AccessPermission:Read_Write, desc="Blocked on memory write, will go to E";
WB_E_W, AccessPermission:Busy, desc="Blocked on memory write, will go to E";
NO_F, AccessPermission:Busy, desc="Blocked on a flush";
NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
@ -199,7 +199,17 @@ machine(Directory, "AMD Hammer-like protocol")
}
DataBlock getDataBlock(Address addr), return_by_ref="yes" {
return getDirectoryEntry(addr).DataBlk;
Entry dir_entry := getDirectoryEntry(addr);
if(is_valid(dir_entry)) {
return dir_entry.DataBlk;
}
TBE tbe := TBEs[addr];
if(is_valid(tbe)) {
return tbe.DataBlk;
}
error("Data block missing!");
}
PfEntry getProbeFilterEntry(Address addr), return_by_pointer="yes" {
@ -1168,9 +1178,7 @@ machine(Directory, "AMD Hammer-like protocol")
}
action(l_writeDataToMemory, "l", desc="Write PUTX/PUTO data to memory") {
peek(unblockNetwork_in, ResponseMsg) {
assert(in_msg.Dirty);
assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
peek(memQueue_in, MemoryMsg) {
getDirectoryEntry(address).DataBlk := in_msg.DataBlk;
DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n",
in_msg.Address, in_msg.DataBlk);
@ -1236,8 +1244,11 @@ machine(Directory, "AMD Hammer-like protocol")
action(l_queueMemoryWBRequest, "lq", desc="Write PUTX data to memory") {
peek(unblockNetwork_in, ResponseMsg) {
enqueue(memQueue_out, MemoryMsg, latency="1") {
assert(in_msg.Dirty);
assert(in_msg.MessageSize == MessageSizeType:Writeback_Data);
out_msg.Address := address;
out_msg.Type := MemoryRequestType:MEMORY_WB;
out_msg.DataBlk := in_msg.DataBlk;
DPRINTF(RubySlicc, "%s\n", out_msg);
}
}
@ -1854,26 +1865,26 @@ machine(Directory, "AMD Hammer-like protocol")
// WB State Transistions
transition(WB, Writeback_Dirty, WB_O_W) {
l_writeDataToMemory;
rs_removeSharer;
l_queueMemoryWBRequest;
j_popIncomingUnblockQueue;
}
transition(WB, Writeback_Exclusive_Dirty, WB_E_W) {
l_writeDataToMemory;
rs_removeSharer;
l_queueMemoryWBRequest;
j_popIncomingUnblockQueue;
}
transition(WB_E_W, Memory_Ack, E) {
l_writeDataToMemory;
pfd_probeFilterDeallocate;
k_wakeUpDependents;
l_popMemQueue;
}
transition(WB_O_W, Memory_Ack, O) {
l_writeDataToMemory;
k_wakeUpDependents;
l_popMemQueue;
}

View file

@ -73,6 +73,16 @@ enumeration(TriggerType, desc="...") {
structure(TriggerMsg, desc="...", interface="Message") {
Address Address, desc="Physical address for this request";
TriggerType Type, desc="Type of trigger";
bool functionalRead(Packet *pkt) {
// Trigger messages do not hold any data!
return false;
}
bool functionalWrite(Packet *pkt) {
// Trigger messages do not hold any data!
return false;
}
}
// RequestMsg (and also forwarded requests)
@ -87,6 +97,16 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
Time InitialRequestTime, default="0", desc="time the initial requests was sent from the L1Cache";
Time ForwardRequestTime, default="0", desc="time the dir forwarded the request";
int SilentAcks, default="0", desc="silent acks from the full-bit directory";
bool functionalRead(Packet *pkt) {
// Request messages do not hold any data
return false;
}
bool functionalWrite(Packet *pkt) {
// Request messages do not hold any data
return false;
}
}
// ResponseMsg (and also unblock requests)
@ -103,6 +123,27 @@ structure(ResponseMsg, desc="...", interface="NetworkMessage") {
Time InitialRequestTime, default="0", desc="time the initial requests was sent from the L1Cache";
Time ForwardRequestTime, default="0", desc="time the dir forwarded the request";
int SilentAcks, default="0", desc="silent acks from the full-bit directory";
bool functionalRead(Packet *pkt) {
// The check below ensures that data is read only from messages that
// actually hold data.
if (Type == CoherenceResponseType:DATA ||
Type == CoherenceResponseType:DATA_SHARED ||
Type == CoherenceResponseType:DATA_EXCLUSIVE ||
Type == CoherenceResponseType:WB_DIRTY ||
Type == CoherenceResponseType:WB_EXCLUSIVE_DIRTY) {
return testAndRead(Address, DataBlk, pkt);
}
return false;
}
bool functionalWrite(Packet *pkt) {
// Message type does not matter since all messages are written.
// If a protocol reads data from a packet that is not supposed
// to hold the data, then the fault lies with the protocol.
return testAndWrite(Address, DataBlk, pkt);
}
}
enumeration(DMARequestType, desc="...", default="DMARequestType_NULL") {
@ -126,6 +167,14 @@ structure(DMARequestMsg, desc="...", interface="NetworkMessage") {
DataBlock DataBlk, desc="DataBlk attached to this request";
int Len, desc="The length of the request";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
return testAndRead(LineAddress, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(LineAddress, DataBlk, pkt);
}
}
structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
@ -135,4 +184,12 @@ structure(DMAResponseMsg, desc="...", interface="NetworkMessage") {
NetDest Destination, desc="Destination";
DataBlock DataBlk, desc="DataBlk attached to this request";
MessageSizeType MessageSize, desc="size category of the message";
bool functionalRead(Packet *pkt) {
return testAndRead(LineAddress, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(LineAddress, DataBlk, pkt);
}
}

View file

@ -40,4 +40,8 @@ structure(RequestMsg, desc="...", interface="NetworkMessage") {
NetDest Destination, desc="Multicast destination mask";
DataBlock DataBlk, desc="data for the cache line";
MessageSizeType MessageSize, desc="size category of the message";
void functionalWrite(Packet *pkt) {
error("Network test does not support functional accesses!");
}
}

View file

@ -27,24 +27,23 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* $Id$
*
*/
// defines
// Declarations of external types that are common to all protocols
external_type(int, primitive="yes", default="0");
external_type(bool, primitive="yes", default="false");
external_type(std::string, primitive="yes");
external_type(uint64, primitive="yes");
external_type(Time, primitive="yes", default="0");
external_type(PacketPtr, primitive="yes");
external_type(Packet, primitive="yes");
external_type(Address);
structure(DataBlock, external = "yes", desc="..."){
void clear();
void copyPartial(DataBlock, int, int);
}
// Declarations of external types that are common to all protocols
bool testAndRead(Address addr, DataBlock datablk, Packet *pkt);
bool testAndWrite(Address addr, DataBlock datablk, Packet *pkt);
// AccessPermission
// The following five states define the access permission of all memory blocks.
@ -265,6 +264,14 @@ structure(SequencerMsg, desc="...", interface="Message") {
DataBlock DataBlk, desc="Data";
int Len, desc="size in bytes of access";
PrefetchBit Prefetch, desc="Is this a prefetch request";
bool functionalRead(Packet *pkt) {
return testAndRead(PhysicalAddress, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(PhysicalAddress, DataBlk, pkt);
}
}
// MaskPredictorType

View file

@ -61,4 +61,12 @@ structure(MemoryMsg, desc="...", interface="Message") {
PrefetchBit Prefetch, desc="Is this a prefetch request";
bool ReadX, desc="Exclusive";
int Acks, desc="How many acks to expect";
bool functionalRead(Packet *pkt) {
return testAndRead(Address, DataBlk, pkt);
}
bool functionalWrite(Packet *pkt) {
return testAndWrite(Address, DataBlk, pkt);
}
}

View file

@ -435,3 +435,69 @@ MessageBuffer::printStats(ostream& out)
out << "MessageBuffer: " << m_name << " stats - msgs:" << m_msg_counter
<< " full:" << m_not_avail_count << endl;
}
bool
MessageBuffer::isReady() const
{
return ((m_prio_heap.size() > 0) &&
(m_prio_heap.front().m_time <= g_system_ptr->getTime()));
}
bool
MessageBuffer::functionalRead(Packet *pkt)
{
// Check the priority heap and read any messages that may
// correspond to the address in the packet.
for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
Message *msg = m_prio_heap[i].m_msgptr.get();
if (msg->functionalRead(pkt)) return true;
}
// Read the messages in the stall queue that correspond
// to the address in the packet.
for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
map_iter != m_stall_msg_map.end();
++map_iter) {
for (std::list<MsgPtr>::iterator it = (map_iter->second).begin();
it != (map_iter->second).end(); ++it) {
Message *msg = (*it).get();
if (msg->functionalRead(pkt)) return true;
}
}
return false;
}
uint32_t
MessageBuffer::functionalWrite(Packet *pkt)
{
uint32_t num_functional_writes = 0;
// Check the priority heap and write any messages that may
// correspond to the address in the packet.
for (unsigned int i = 0; i < m_prio_heap.size(); ++i) {
Message *msg = m_prio_heap[i].m_msgptr.get();
if (msg->functionalWrite(pkt)) {
num_functional_writes++;
}
}
// Check the stall queue and write any messages that may
// correspond to the address in the packet.
for (StallMsgMapType::iterator map_iter = m_stall_msg_map.begin();
map_iter != m_stall_msg_map.end();
++map_iter) {
for (std::list<MsgPtr>::iterator it = (map_iter->second).begin();
it != (map_iter->second).end(); ++it) {
Message *msg = (*it).get();
if (msg->functionalWrite(pkt)) {
num_functional_writes++;
}
}
}
return num_functional_writes;
}

View file

@ -41,10 +41,10 @@
#include <string>
#include <vector>
#include "mem/packet.hh"
#include "mem/ruby/buffers/MessageBufferNode.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/slicc_interface/Message.hh"
class MessageBuffer
@ -65,12 +65,7 @@ class MessageBuffer
void stallMessage(const Address& addr);
// TRUE if head of queue timestamp <= SystemTime
bool
isReady() const
{
return ((m_prio_heap.size() > 0) &&
(m_prio_heap.front().m_time <= g_system_ptr->getTime()));
}
bool isReady() const;
void
delayHead()
@ -145,6 +140,17 @@ class MessageBuffer
void setIncomingLink(int link_id) { m_input_link_id = link_id; }
void setVnet(int net) { m_vnet_id = net; }
// Function for figuring out if any of the messages in the buffer can
// satisfy the read request for the address in the packet.
// Return value, if true, indicates that the request was fulfilled.
bool functionalRead(Packet *pkt);
// Function for figuring out if any of the messages in the buffer need
// to be updated with the data from the packet.
// Return value indicates the number of messages that were updated.
// This required for debugging the code.
uint32_t functionalWrite(Packet *pkt);
private:
//added by SS
int m_recycle_latency;

View file

@ -31,7 +31,6 @@
#include <iostream>
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/slicc_interface/Message.hh"
class MessageBufferNode

View file

@ -44,6 +44,7 @@
#include <string>
#include <vector>
#include "mem/packet.hh"
#include "mem/protocol/LinkDirection.hh"
#include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/common/TypeDefines.hh"
@ -94,6 +95,16 @@ class Network : public SimObject
virtual void clearStats() = 0;
virtual void print(std::ostream& out) const = 0;
/*
* Virtual functions for functionally reading and writing packets in
* the network. Each network needs to implement these for functional
* accesses to work correctly.
*/
virtual bool functionalRead(Packet *pkt)
{ fatal("Functional read not implemented.\n"); }
virtual uint32_t functionalWrite(Packet *pkt)
{ fatal("Functional write not implemented.\n"); }
protected:
// Private copy constructor and assignment operator
Network(const Network& obj);

View file

@ -343,4 +343,3 @@ PerfectSwitch::print(std::ostream& out) const
{
out << "[PerfectSwitch " << m_switch_id << "]";
}

View file

@ -327,3 +327,41 @@ SimpleNetworkParams::create()
{
return new SimpleNetwork(this);
}
/*
* The simple network has an array of switches. These switches have buffers
* that need to be accessed for functional reads and writes. Also the links
* between different switches have buffers that need to be accessed.
*/
bool
SimpleNetwork::functionalRead(Packet *pkt)
{
for (unsigned int i = 0; i < m_switch_ptr_vector.size(); i++) {
if (m_switch_ptr_vector[i]->functionalRead(pkt)) {
return true;
}
}
for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
if (m_buffers_to_free[i]->functionalRead(pkt)) {
return true;
}
}
return false;
}
uint32_t
SimpleNetwork::functionalWrite(Packet *pkt)
{
uint32_t num_functional_writes = 0;
for (unsigned int i = 0; i < m_switch_ptr_vector.size(); i++) {
num_functional_writes += m_switch_ptr_vector[i]->functionalWrite(pkt);
}
for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
num_functional_writes += m_buffers_to_free[i]->functionalWrite(pkt);
}
return num_functional_writes;
}

View file

@ -86,6 +86,9 @@ class SimpleNetwork : public Network
void print(std::ostream& out) const;
bool functionalRead(Packet *pkt);
uint32_t functionalWrite(Packet *pkt);
private:
void checkNetworkAllocation(NodeID id, bool ordered, int network_num);
void addLink(SwitchID src, SwitchID dest, int link_latency);

View file

@ -217,6 +217,28 @@ Switch::print(std::ostream& out) const
// FIXME printing
out << "[Switch]";
}
bool
Switch::functionalRead(Packet *pkt)
{
// Access the buffers in the switch for performing a functional read
for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
if (m_buffers_to_free[i]->functionalRead(pkt)) {
return true;
}
}
return false;
}
uint32_t
Switch::functionalWrite(Packet *pkt)
{
// Access the buffers in the switch for performing a functional write
uint32_t num_functional_writes = 0;
for (unsigned int i = 0; i < m_buffers_to_free.size(); ++i) {
num_functional_writes += m_buffers_to_free[i]->functionalWrite(pkt);
}
return num_functional_writes;
}
Switch *
SwitchParams::create()

View file

@ -74,6 +74,9 @@ class Switch : public BasicRouter
void print(std::ostream& out) const;
void init_net_ptr(SimpleNetwork* net_ptr) { m_network_ptr = net_ptr; }
bool functionalRead(Packet *);
uint32_t functionalWrite(Packet *);
private:
// Private copy constructor and assignment operator
Switch(const Switch& obj);

View file

@ -32,6 +32,7 @@
#include <iostream>
#include <string>
#include "mem/packet.hh"
#include "mem/protocol/AccessPermission.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
@ -68,6 +69,15 @@ class AbstractController : public SimObject, public Consumer
virtual void clearStats() = 0;
virtual void recordCacheTrace(int cntrl, CacheRecorder* tr) = 0;
virtual Sequencer* getSequencer() const = 0;
//! These functions are used by ruby system to read/write the message
//! queues that exist with in the controller.
//! The boolean return value indicates if the read was performed
//! successfully.
virtual bool functionalReadBuffers(PacketPtr&) = 0;
//! The return value indicates the number of messages written with the
//! data from the packet.
virtual uint32_t functionalWriteBuffers(PacketPtr&) = 0;
};
#endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__

View file

@ -61,6 +61,18 @@ class Message : public RefCounted
virtual void setIncomingLink(int) {}
virtual void setVnet(int) {}
/**
* The two functions below are used for reading / writing the message
* functionally. The methods return true if the address in the packet
* matches the address / address range in the message. Each message
* class that can be potentially searched for the address needs to
* implement these methods.
*/
virtual bool functionalRead(Packet *pkt) = 0;
//{ fatal("Read functional access not implemented!"); }
virtual bool functionalWrite(Packet *pkt) = 0;
//{ fatal("Write functional access not implemented!"); }
void setDelayedCycles(const int& cycles) { m_DelayedCycles = cycles; }
const int& getDelayedCycles() const {return m_DelayedCycles;}
int& getDelayedCycles() {return m_DelayedCycles;}

View file

@ -33,7 +33,6 @@
#include "base/refcnt.hh"
#include "mem/protocol/MessageSizeType.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/common/NetDest.hh"
#include "mem/ruby/slicc_interface/Message.hh"

View file

@ -18,3 +18,40 @@ RubyRequest::print(ostream& out) const
// out << "Time = " << getTime() << " ";
out << "]";
}
bool
RubyRequest::functionalRead(Packet *pkt)
{
// This needs a little explanation. Initially I thought that this
// message should be read. But the way the memtester works for now,
// we should not be reading this message as memtester updates the
// functional memory only after a write has actually taken place.
return false;
}
bool
RubyRequest::functionalWrite(Packet *pkt)
{
// This needs a little explanation. I am not sure if this message
// should be written. Essentially the question is how are writes
// ordered. I am assuming that if a functional write is issued after
// a timing write to the same address, then the functional write
// has to overwrite the data for the timing request, even if the
// timing request has still not been ordered globally.
Address pktLineAddr(pkt->getAddr());
pktLineAddr.makeLineAddress();
if (pktLineAddr == m_LineAddress) {
uint8_t *pktData = pkt->getPtr<uint8_t>(true);
unsigned int size_in_bytes = pkt->getSize();
unsigned startByte = pkt->getAddr() - m_LineAddress.getAddress();
for (unsigned i = 0; i < size_in_bytes; ++i) {
data[i + startByte] = pktData[i];
}
return true;
}
return false;
}

View file

@ -126,6 +126,9 @@ class RubyRequest : public Message
}
void print(std::ostream& out) const;
bool functionalRead(Packet *pkt);
bool functionalWrite(Packet *pkt);
};
inline std::ostream&

View file

@ -35,6 +35,7 @@
#include <cassert>
#include "debug/RubySlicc.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
@ -129,4 +130,60 @@ mod(int val, int mod)
return val % mod;
}
/**
* This function accepts an address, a data block and a packet. If the address
* range for the data block contains the address which the packet needs to
* read, then the data from the data block is written to the packet. True is
* returned if the data block was read, otherwise false is returned.
*/
inline bool
testAndRead(Address addr, DataBlock& blk, Packet *pkt)
{
Address pktLineAddr(pkt->getAddr());
pktLineAddr.makeLineAddress();
Address lineAddr = addr;
lineAddr.makeLineAddress();
if (pktLineAddr == lineAddr) {
uint8_t *data = pkt->getPtr<uint8_t>(true);
unsigned int size_in_bytes = pkt->getSize();
unsigned startByte = pkt->getAddr() - lineAddr.getAddress();
for (unsigned i = 0; i < size_in_bytes; ++i) {
data[i] = blk.getByte(i + startByte);
}
return true;
}
return false;
}
/**
* This function accepts an address, a data block and a packet. If the address
* range for the data block contains the address which the packet needs to
* write, then the data from the packet is written to the data block. True is
* returned if the data block was written, otherwise false is returned.
*/
inline bool
testAndWrite(Address addr, DataBlock& blk, Packet *pkt)
{
Address pktLineAddr(pkt->getAddr());
pktLineAddr.makeLineAddress();
Address lineAddr = addr;
lineAddr.makeLineAddress();
if (pktLineAddr == lineAddr) {
uint8_t *data = pkt->getPtr<uint8_t>(true);
unsigned int size_in_bytes = pkt->getSize();
unsigned startByte = pkt->getAddr() - lineAddr.getAddress();
for (unsigned i = 0; i < size_in_bytes; ++i) {
blk.setByte(i + startByte, data[i]);
}
return true;
}
return false;
}
#endif // __MEM_RUBY_SLICC_INTERFACE_RUBYSLICCUTIL_HH__

View file

@ -27,18 +27,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "base/cast.hh"
#include "base/cprintf.hh"
#include "debug/RubyStats.hh"
#include "mem/ruby/common/Address.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/common/Global.hh"
#include "mem/ruby/network/Network.hh"
#include "mem/ruby/profiler/Profiler.hh"
#include "mem/ruby/slicc_interface/NetworkMessage.hh"
#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
#include "mem/ruby/system/MemoryControl.hh"
#include "mem/ruby/system/RubyMemoryControl.hh"
#include "mem/ruby/system/System.hh"
using namespace std;
@ -55,9 +47,3 @@ MemoryControl::recordRequestType(MemoryControlRequestType request) {
DPRINTF(RubyStats, "Recorded request: %s\n",
MemoryControlRequestType_to_string(request));
}
RubyMemoryControl *
RubyMemoryControlParams::create()
{
return new RubyMemoryControl(this);
}

View file

@ -35,19 +35,14 @@
#include <string>
#include "mem/protocol/MemoryControlRequestType.hh"
#include "mem/protocol/MemoryMsg.hh"
#include "mem/ruby/common/Consumer.hh"
#include "mem/ruby/profiler/MemCntrlProfiler.hh"
#include "mem/ruby/slicc_interface/Message.hh"
#include "mem/ruby/system/MemoryNode.hh"
#include "mem/ruby/system/System.hh"
#include "params/MemoryControl.hh"
#include "sim/clocked_object.hh"
//////////////////////////////////////////////////////////////////////////////
class Consumer;
class MemoryControl : public ClockedObject, public Consumer
{
public:
@ -97,6 +92,11 @@ class MemoryControl : public ClockedObject, public Consumer
virtual void recordRequestType(MemoryControlRequestType requestType);
virtual bool functionalReadBuffers(Packet *pkt)
{ fatal("Functional read access not implemented!");}
virtual uint32_t functionalWriteBuffers(Packet *pkt)
{ fatal("Functional read access not implemented!");}
protected:
class MemCntrlEvent : public Event
{

View file

@ -708,3 +708,91 @@ RubyMemoryControl::wakeup()
}
}
/**
* This function reads the different buffers that exist in the Ruby Memory
* Controller, and figures out if any of the buffers hold a message that
* contains the data for the address provided in the packet. True is returned
* if any of the messages was read, otherwise false is returned.
*
* I think we should move these buffers to being message buffers, instead of
* being lists.
*/
bool
RubyMemoryControl::functionalReadBuffers(Packet *pkt)
{
for (std::list<MemoryNode>::iterator it = m_input_queue.begin();
it != m_input_queue.end(); ++it) {
Message* msg_ptr = (*it).m_msgptr.get();
if (msg_ptr->functionalRead(pkt)) {
return true;
}
}
for (std::list<MemoryNode>::iterator it = m_response_queue.begin();
it != m_response_queue.end(); ++it) {
Message* msg_ptr = (*it).m_msgptr.get();
if (msg_ptr->functionalRead(pkt)) {
return true;
}
}
for (uint32_t bank = 0; bank < m_total_banks; ++bank) {
for (std::list<MemoryNode>::iterator it = m_bankQueues[bank].begin();
it != m_bankQueues[bank].end(); ++it) {
Message* msg_ptr = (*it).m_msgptr.get();
if (msg_ptr->functionalRead(pkt)) {
return true;
}
}
}
return false;
}
/**
* This function reads the different buffers that exist in the Ruby Memory
* Controller, and figures out if any of the buffers hold a message that
* needs to functionally written with the data in the packet.
*
* The number of messages written is returned at the end. This is required
* for debugging purposes.
*/
uint32_t
RubyMemoryControl::functionalWriteBuffers(Packet *pkt)
{
uint32_t num_functional_writes = 0;
for (std::list<MemoryNode>::iterator it = m_input_queue.begin();
it != m_input_queue.end(); ++it) {
Message* msg_ptr = (*it).m_msgptr.get();
if (msg_ptr->functionalWrite(pkt)) {
num_functional_writes++;
}
}
for (std::list<MemoryNode>::iterator it = m_response_queue.begin();
it != m_response_queue.end(); ++it) {
Message* msg_ptr = (*it).m_msgptr.get();
if (msg_ptr->functionalWrite(pkt)) {
num_functional_writes++;
}
}
for (uint32_t bank = 0; bank < m_total_banks; ++bank) {
for (std::list<MemoryNode>::iterator it = m_bankQueues[bank].begin();
it != m_bankQueues[bank].end(); ++it) {
Message* msg_ptr = (*it).m_msgptr.get();
if (msg_ptr->functionalWrite(pkt)) {
num_functional_writes++;
}
}
}
return num_functional_writes;
}
RubyMemoryControl *
RubyMemoryControlParams::create()
{
return new RubyMemoryControl(this);
}

View file

@ -96,6 +96,8 @@ class RubyMemoryControl : public MemoryControl
int getRanksPerDimm() { return m_ranks_per_dimm; };
int getDimmsPerChannel() { return m_dimms_per_channel; }
bool functionalReadBuffers(Packet *pkt);
uint32_t functionalWriteBuffers(Packet *pkt);
private:
void enqueueToDirectory(MemoryNode req, int latency);

View file

@ -417,7 +417,7 @@ RubySystem::functionalRead(PacketPtr pkt)
// 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) {
for (unsigned int i = 0; i < num_controllers; ++i) {
access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address);
if (access_perm == AccessPermission_Read_Only)
num_ro++;
@ -452,7 +452,7 @@ RubySystem::functionalRead(PacketPtr pkt)
if (num_invalid == (num_controllers - 1) &&
num_backing_store == 1) {
DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n");
for (int i = 0; i < num_controllers; ++i) {
for (unsigned int i = 0; i < num_controllers; ++i) {
access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address);
if (access_perm == AccessPermission_Backing_Store) {
DataBlock& block = m_abs_cntrl_vec[i]->
@ -466,7 +466,7 @@ RubySystem::functionalRead(PacketPtr pkt)
return true;
}
}
} else {
} else if (num_ro > 0 || num_rw == 1) {
// 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
@ -476,7 +476,7 @@ RubySystem::functionalRead(PacketPtr pkt)
// 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) {
for (unsigned int i = 0;i < num_controllers;++i) {
access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address);
if (access_perm == AccessPermission_Read_Only ||
access_perm == AccessPermission_Read_Write) {
@ -492,9 +492,34 @@ RubySystem::functionalRead(PacketPtr pkt)
}
}
}
// Since we are here, this means that none of the controllers hold this
// address in a stable/base state. The function searches through all the
// buffers that exist in different cache, directory and memory
// controllers, and in the network components and reads the data portion
// of the first message that holds address specified in the packet.
for (unsigned int i = 0; i < num_controllers;++i) {
if (m_abs_cntrl_vec[i]->functionalReadBuffers(pkt)) {
return true;
}
}
for (unsigned int i = 0; i < m_memory_controller_vec.size(); ++i) {
if (m_memory_controller_vec[i]->functionalReadBuffers(pkt)) {
return true;
}
}
if (m_network_ptr->functionalRead(pkt)) {
return true;
}
return false;
}
// The function searches through all the buffers that exist in different
// cache, directory and memory controllers, and in the network components
// and writes the data portion of those that hold the address specified
// in the packet.
bool
RubySystem::functionalWrite(PacketPtr pkt)
{
@ -505,57 +530,16 @@ RubySystem::functionalWrite(PacketPtr pkt)
DPRINTF(RubySystem, "Functional Write request for %s\n",addr);
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 = m_abs_cntrl_vec[i]->getAccessPermission(line_addr);
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. 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(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n",
num_busy, num_ro, num_rw);
assert(num_rw <= 1);
uint8_t *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) {
for (unsigned int i = 0; i < num_controllers;++i) {
m_abs_cntrl_vec[i]->functionalWriteBuffers(pkt);
access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr);
if (access_perm == AccessPermission_Read_Only ||
access_perm == AccessPermission_Read_Write||
access_perm == AccessPermission_Maybe_Stale ||
access_perm == AccessPermission_Backing_Store) {
if (access_perm != AccessPermission_Invalid &&
access_perm != AccessPermission_NotPresent) {
DataBlock& block = m_abs_cntrl_vec[i]->getDataBlock(line_addr);
DPRINTF(RubySystem, "%s\n",block);
@ -565,9 +549,17 @@ RubySystem::functionalWrite(PacketPtr pkt)
DPRINTF(RubySystem, "%s\n",block);
}
}
return true;
uint32_t M5_VAR_USED num_functional_writes = 0;
for (unsigned int i = 0; i < m_memory_controller_vec.size() ;++i) {
num_functional_writes +=
m_memory_controller_vec[i]->functionalWriteBuffers(pkt);
}
return false;
num_functional_writes += m_network_ptr->functionalWrite(pkt);
DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes);
return true;
}
#ifdef CHECK_COHERENCE

View file

@ -60,7 +60,10 @@ class TypeDeclAST(DeclAST):
machine.addType(new_type)
self.symtab.newSymbol(new_type)
self.symtab.pushFrame()
# Add all of the fields of the type to it
for field in self.field_asts:
field.generate(new_type)
self.symtab.popFrame()

View file

@ -269,6 +269,9 @@ class $c_ident : public AbstractController
void recordCacheTrace(int cntrl, CacheRecorder* tr);
Sequencer* getSequencer() const;
bool functionalReadBuffers(PacketPtr&);
uint32_t functionalWriteBuffers(PacketPtr&);
private:
''')
@ -987,6 +990,39 @@ $c_ident::${{action.ident}}(const Address& addr)
for func in self.functions:
code(func.generateCode())
# Function for functional reads from messages buffered in the controller
code('''
bool
$c_ident::functionalReadBuffers(PacketPtr& pkt)
{
''')
for var in self.objects:
vtype = var.type
if vtype.isBuffer:
vid = "m_%s_ptr" % var.c_ident
code('if ($vid->functionalRead(pkt)) { return true; }')
code('''
return false;
}
''')
# Function for functional writes to messages buffered in the controller
code('''
uint32_t
$c_ident::functionalWriteBuffers(PacketPtr& pkt)
{
uint32_t num_functional_writes = 0;
''')
for var in self.objects:
vtype = var.type
if vtype.isBuffer:
vid = "m_%s_ptr" % var.c_ident
code('num_functional_writes += $vid->functionalWrite(pkt);')
code('''
return num_functional_writes;
}
''')
code.write(path, "%s.cc" % c_ident)
def printCWakeup(self, path, includes):

View file

@ -81,8 +81,7 @@ class SymbolTable(object):
if types is not None:
if not isinstance(symbol, types):
symbol.error("Symbol '%s' is not of types '%s'.",
symbol,
types)
symbol, types)
return symbol

View file

@ -29,6 +29,7 @@ from m5.util import orderdict
from slicc.util import PairContainer
from slicc.symbols.Symbol import Symbol
from slicc.symbols.Var import Var
class DataMember(PairContainer):
def __init__(self, ident, type, pairs, init_code):
@ -151,6 +152,9 @@ class Type(Symbol):
member = DataMember(ident, type, pairs, init_code)
self.data_members[ident] = member
var = Var(self.symtab, ident, self.location, type,
"m_%s" % ident, {}, None)
self.symtab.registerSym(ident, var)
return True
def dataMemberType(self, ident):
@ -415,6 +419,7 @@ operator<<(std::ostream& out, const ${{self.c_ident}}& obj)
#include <iostream>
#include "mem/protocol/${{self.c_ident}}.hh"
#include "mem/ruby/slicc_interface/RubySlicc_Util.hh"
using namespace std;
''')