diff options
45 files changed, 802 insertions, 138 deletions
diff --git a/configs/example/ruby_mem_test.py b/configs/example/ruby_mem_test.py index 858d13ee8..1d3e20412 100644 --- a/configs/example/ruby_mem_test.py +++ b/configs/example/ruby_mem_test.py @@ -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) diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm index d54f7e71c..eb8e62d30 100644 --- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm @@ -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; } diff --git a/src/mem/protocol/MESI_CMP_directory-L2cache.sm b/src/mem/protocol/MESI_CMP_directory-L2cache.sm index 88053aeb8..fbdc10ac2 100644 --- a/src/mem/protocol/MESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L2cache.sm @@ -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; } diff --git a/src/mem/protocol/MESI_CMP_directory-dir.sm b/src/mem/protocol/MESI_CMP_directory-dir.sm index 7e1280337..d98326b34 100644 --- a/src/mem/protocol/MESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MESI_CMP_directory-dir.sm @@ -110,7 +110,7 @@ machine(Directory, "MESI_CMP_filter_directory protocol") void set_tbe(TBE tbe); void unset_tbe(); void wakeUpBuffers(Address a); - + Entry getDirectoryEntry(Address addr), return_by_pointer="yes" { Entry dir_entry := static_cast(Entry, "pointer", directory[addr]); @@ -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; } diff --git a/src/mem/protocol/MESI_CMP_directory-msg.sm b/src/mem/protocol/MESI_CMP_directory-msg.sm index 67619f075..473012c61 100644 --- a/src/mem/protocol/MESI_CMP_directory-msg.sm +++ b/src/mem/protocol/MESI_CMP_directory-msg.sm @@ -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"; @@ -47,14 +45,14 @@ 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"; - ACK, desc="Generic invalidate ack"; - WB_ACK, desc="writeback ack"; - UNBLOCK, desc="unblock"; - EXCLUSIVE_UNBLOCK, desc="exclusive unblock"; + MEMORY_ACK, desc="Ack from memory controller"; + 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"; + EXCLUSIVE_UNBLOCK, desc="exclusive unblock"; INV, desc="Invalidate from directory"; } @@ -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); + } } diff --git a/src/mem/protocol/MI_example-cache.sm b/src/mem/protocol/MI_example-cache.sm index cf5cf9505..5040eb85d 100644 --- a/src/mem/protocol/MI_example-cache.sm +++ b/src/mem/protocol/MI_example-cache.sm @@ -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; } diff --git a/src/mem/protocol/MI_example-dir.sm b/src/mem/protocol/MI_example-dir.sm index 241ad3b30..f15ccb14e 100644 --- a/src/mem/protocol/MI_example-dir.sm +++ b/src/mem/protocol/MI_example-dir.sm @@ -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; diff --git a/src/mem/protocol/MI_example-msg.sm b/src/mem/protocol/MI_example-msg.sm index 2fb1c48ba..0645371f6 100644 --- a/src/mem/protocol/MI_example-msg.sm +++ b/src/mem/protocol/MI_example-msg.sm @@ -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); + } } diff --git a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm index 43c2def2e..6295f90fd 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm @@ -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) { diff --git a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm index 6238953ad..2e4e66a7b 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm @@ -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; } diff --git a/src/mem/protocol/MOESI_CMP_directory-dir.sm b/src/mem/protocol/MOESI_CMP_directory-dir.sm index 1635267f6..0dd4239a9 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm @@ -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); } } diff --git a/src/mem/protocol/MOESI_CMP_directory-msg.sm b/src/mem/protocol/MOESI_CMP_directory-msg.sm index 7b203537f..e428be7f7 100644 --- a/src/mem/protocol/MOESI_CMP_directory-msg.sm +++ b/src/mem/protocol/MOESI_CMP_directory-msg.sm @@ -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); + } } diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm index b6de5a714..8cf40974e 100644 --- a/src/mem/protocol/MOESI_CMP_token-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm @@ -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"; diff --git a/src/mem/protocol/MOESI_CMP_token-dir.sm b/src/mem/protocol/MOESI_CMP_token-dir.sm index 8d78be40c..fd51e2924 100644 --- a/src/mem/protocol/MOESI_CMP_token-dir.sm +++ b/src/mem/protocol/MOESI_CMP_token-dir.sm @@ -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); } } diff --git a/src/mem/protocol/MOESI_CMP_token-msg.sm b/src/mem/protocol/MOESI_CMP_token-msg.sm index b1c3f4580..6a8d6c6bc 100644 --- a/src/mem/protocol/MOESI_CMP_token-msg.sm +++ b/src/mem/protocol/MOESI_CMP_token-msg.sm @@ -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); + } } diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm index 6eb0974b0..a3fa1219f 100644 --- a/src/mem/protocol/MOESI_hammer-cache.sm +++ b/src/mem/protocol/MOESI_hammer-cache.sm @@ -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; } diff --git a/src/mem/protocol/MOESI_hammer-dir.sm b/src/mem/protocol/MOESI_hammer-dir.sm index ed1fb7669..22ca568a8 100644 --- a/src/mem/protocol/MOESI_hammer-dir.sm +++ b/src/mem/protocol/MOESI_hammer-dir.sm @@ -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" { @@ -222,7 +232,7 @@ machine(Directory, "AMD Hammer-like protocol") return getDirectoryEntry(addr).DirectoryState; } } - + void setState(TBE tbe, PfEntry pf_entry, Address addr, State state) { if (is_valid(tbe)) { tbe.TBEState := state; @@ -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; } diff --git a/src/mem/protocol/MOESI_hammer-msg.sm b/src/mem/protocol/MOESI_hammer-msg.sm index 6ead7200a..41d176a9c 100644 --- a/src/mem/protocol/MOESI_hammer-msg.sm +++ b/src/mem/protocol/MOESI_hammer-msg.sm @@ -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); + } } diff --git a/src/mem/protocol/Network_test-msg.sm b/src/mem/protocol/Network_test-msg.sm index 6492024d8..9e21d39bb 100644 --- a/src/mem/protocol/Network_test-msg.sm +++ b/src/mem/protocol/Network_test-msg.sm @@ -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!"); + } } diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm index b42f9c3a9..2a4281757 100644 --- a/src/mem/protocol/RubySlicc_Exports.sm +++ b/src/mem/protocol/RubySlicc_Exports.sm @@ -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 diff --git a/src/mem/protocol/RubySlicc_MemControl.sm b/src/mem/protocol/RubySlicc_MemControl.sm index 66bb37bca..08bff6e36 100644 --- a/src/mem/protocol/RubySlicc_MemControl.sm +++ b/src/mem/protocol/RubySlicc_MemControl.sm @@ -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); + } } diff --git a/src/mem/ruby/buffers/MessageBuffer.cc b/src/mem/ruby/buffers/MessageBuffer.cc index f0d372a52..f960cc033 100644 --- a/src/mem/ruby/buffers/MessageBuffer.cc +++ b/src/mem/ruby/buffers/MessageBuffer.cc @@ -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; +} diff --git a/src/mem/ruby/buffers/MessageBuffer.hh b/src/mem/ruby/buffers/MessageBuffer.hh index cf7e77c2d..c4fd7165d 100644 --- a/src/mem/ruby/buffers/MessageBuffer.hh +++ b/src/mem/ruby/buffers/MessageBuffer.hh @@ -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; diff --git a/src/mem/ruby/buffers/MessageBufferNode.hh b/src/mem/ruby/buffers/MessageBufferNode.hh index 70afa9831..5e7a52e12 100644 --- a/src/mem/ruby/buffers/MessageBufferNode.hh +++ b/src/mem/ruby/buffers/MessageBufferNode.hh @@ -31,7 +31,6 @@ #include <iostream> -#include "mem/ruby/common/Global.hh" #include "mem/ruby/slicc_interface/Message.hh" class MessageBufferNode diff --git a/src/mem/ruby/network/Network.hh b/src/mem/ruby/network/Network.hh index e9c5a98b7..9236a2207 100644 --- a/src/mem/ruby/network/Network.hh +++ b/src/mem/ruby/network/Network.hh @@ -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" @@ -81,7 +82,7 @@ class Network : public SimObject bool isReconfiguration) = 0; virtual void makeInLink(NodeID src, SwitchID dest, BasicLink* link, LinkDirection direction, - const NetDest& routing_table_entry, + const NetDest& routing_table_entry, bool isReconfiguration) = 0; virtual void makeInternalLink(SwitchID src, SwitchID dest, BasicLink* link, LinkDirection direction, @@ -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); diff --git a/src/mem/ruby/network/simple/PerfectSwitch.cc b/src/mem/ruby/network/simple/PerfectSwitch.cc index 2c845683d..b38b6d539 100644 --- a/src/mem/ruby/network/simple/PerfectSwitch.cc +++ b/src/mem/ruby/network/simple/PerfectSwitch.cc @@ -343,4 +343,3 @@ PerfectSwitch::print(std::ostream& out) const { out << "[PerfectSwitch " << m_switch_id << "]"; } - diff --git a/src/mem/ruby/network/simple/SimpleNetwork.cc b/src/mem/ruby/network/simple/SimpleNetwork.cc index 7aa8e62f9..9df9ed3a5 100644 --- a/src/mem/ruby/network/simple/SimpleNetwork.cc +++ b/src/mem/ruby/network/simple/SimpleNetwork.cc @@ -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; +} diff --git a/src/mem/ruby/network/simple/SimpleNetwork.hh b/src/mem/ruby/network/simple/SimpleNetwork.hh index 6dfaa2724..879446822 100644 --- a/src/mem/ruby/network/simple/SimpleNetwork.hh +++ b/src/mem/ruby/network/simple/SimpleNetwork.hh @@ -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); diff --git a/src/mem/ruby/network/simple/Switch.cc b/src/mem/ruby/network/simple/Switch.cc index 5c2f5a717..a0a27f758 100644 --- a/src/mem/ruby/network/simple/Switch.cc +++ b/src/mem/ruby/network/simple/Switch.cc @@ -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() diff --git a/src/mem/ruby/network/simple/Switch.hh b/src/mem/ruby/network/simple/Switch.hh index 9946e5cc1..05e90f278 100644 --- a/src/mem/ruby/network/simple/Switch.hh +++ b/src/mem/ruby/network/simple/Switch.hh @@ -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); diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh index 70b9968c7..c5cb46f1e 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.hh +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -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__ diff --git a/src/mem/ruby/slicc_interface/Message.hh b/src/mem/ruby/slicc_interface/Message.hh index 48156a99a..7b94a01e2 100644 --- a/src/mem/ruby/slicc_interface/Message.hh +++ b/src/mem/ruby/slicc_interface/Message.hh @@ -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;} diff --git a/src/mem/ruby/slicc_interface/NetworkMessage.hh b/src/mem/ruby/slicc_interface/NetworkMessage.hh index a8f9c625b..d2bcb1241 100644 --- a/src/mem/ruby/slicc_interface/NetworkMessage.hh +++ b/src/mem/ruby/slicc_interface/NetworkMessage.hh @@ -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" diff --git a/src/mem/ruby/slicc_interface/RubyRequest.cc b/src/mem/ruby/slicc_interface/RubyRequest.cc index 2aae61d7b..7ff2b75d8 100644 --- a/src/mem/ruby/slicc_interface/RubyRequest.cc +++ b/src/mem/ruby/slicc_interface/RubyRequest.cc @@ -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; +} diff --git a/src/mem/ruby/slicc_interface/RubyRequest.hh b/src/mem/ruby/slicc_interface/RubyRequest.hh index 870ad1d0e..a4dadc7a7 100644 --- a/src/mem/ruby/slicc_interface/RubyRequest.hh +++ b/src/mem/ruby/slicc_interface/RubyRequest.hh @@ -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& diff --git a/src/mem/ruby/slicc_interface/RubySlicc_Util.hh b/src/mem/ruby/slicc_interface/RubySlicc_Util.hh index 06372c9fc..06c540db5 100644 --- a/src/mem/ruby/slicc_interface/RubySlicc_Util.hh +++ b/src/mem/ruby/slicc_interface/RubySlicc_Util.hh @@ -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__ diff --git a/src/mem/ruby/system/MemoryControl.cc b/src/mem/ruby/system/MemoryControl.cc index c5ddb0c44..e58b36f63 100644 --- a/src/mem/ruby/system/MemoryControl.cc +++ b/src/mem/ruby/system/MemoryControl.cc @@ -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); -} diff --git a/src/mem/ruby/system/MemoryControl.hh b/src/mem/ruby/system/MemoryControl.hh index 7bdc14cfc..8d15b8dec 100644 --- a/src/mem/ruby/system/MemoryControl.hh +++ b/src/mem/ruby/system/MemoryControl.hh @@ -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 { diff --git a/src/mem/ruby/system/RubyMemoryControl.cc b/src/mem/ruby/system/RubyMemoryControl.cc index cfdaaaef7..c0e91c28b 100644 --- a/src/mem/ruby/system/RubyMemoryControl.cc +++ b/src/mem/ruby/system/RubyMemoryControl.cc @@ -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); +} diff --git a/src/mem/ruby/system/RubyMemoryControl.hh b/src/mem/ruby/system/RubyMemoryControl.hh index 98636e408..1f3a8acf5 100644 --- a/src/mem/ruby/system/RubyMemoryControl.hh +++ b/src/mem/ruby/system/RubyMemoryControl.hh @@ -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); diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc index b41f2d727..5ee22e9f5 100644 --- a/src/mem/ruby/system/System.cc +++ b/src/mem/ruby/system/System.cc @@ -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,69 +530,36 @@ 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) { - 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) { + for (unsigned int i = 0; i < num_controllers;++i) { + m_abs_cntrl_vec[i]->functionalWriteBuffers(pkt); - DataBlock& block = m_abs_cntrl_vec[i]->getDataBlock(line_addr); - DPRINTF(RubySystem, "%s\n",block); - for (unsigned i = 0; i < size_in_bytes; ++i) { - block.setByte(i + startByte, data[i]); - } - DPRINTF(RubySystem, "%s\n",block); + access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr); + if (access_perm != AccessPermission_Invalid && + access_perm != AccessPermission_NotPresent) { + + DataBlock& block = m_abs_cntrl_vec[i]->getDataBlock(line_addr); + DPRINTF(RubySystem, "%s\n",block); + for (unsigned i = 0; i < size_in_bytes; ++i) { + block.setByte(i + startByte, data[i]); } + DPRINTF(RubySystem, "%s\n",block); } - return true; } - return false; + + 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); + } + + num_functional_writes += m_network_ptr->functionalWrite(pkt); + DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes); + + return true; } #ifdef CHECK_COHERENCE diff --git a/src/mem/slicc/ast/TypeDeclAST.py b/src/mem/slicc/ast/TypeDeclAST.py index 983e86882..8a58853ac 100644 --- a/src/mem/slicc/ast/TypeDeclAST.py +++ b/src/mem/slicc/ast/TypeDeclAST.py @@ -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() diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index bb69b70bf..427dbf700 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -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): diff --git a/src/mem/slicc/symbols/SymbolTable.py b/src/mem/slicc/symbols/SymbolTable.py index d2c9337f1..43cfe8740 100644 --- a/src/mem/slicc/symbols/SymbolTable.py +++ b/src/mem/slicc/symbols/SymbolTable.py @@ -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 diff --git a/src/mem/slicc/symbols/Type.py b/src/mem/slicc/symbols/Type.py index 383291911..19c144048 100644 --- a/src/mem/slicc/symbols/Type.py +++ b/src/mem/slicc/symbols/Type.py @@ -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; ''') |