diff options
author | Brad Beckmann ext:(%2C%20Nilay%20Vaish%20%3Cnilay%40cs.wisc.edu%3E) <Brad.Beckmann@amd.com> | 2011-06-30 19:49:26 -0500 |
---|---|---|
committer | Brad Beckmann ext:(%2C%20Nilay%20Vaish%20%3Cnilay%40cs.wisc.edu%3E) <Brad.Beckmann@amd.com> | 2011-06-30 19:49:26 -0500 |
commit | c86f849d5a1da1fc77f2fca43b82cb6760f68bc9 (patch) | |
tree | f192cbc73d86ee4e15e752f6ed174e4ce3425c9e /src | |
parent | f4cfd65d2982f0f97304ef05083b40f3346a496f (diff) | |
download | gem5-c86f849d5a1da1fc77f2fca43b82cb6760f68bc9.tar.xz |
Ruby: Add support for functional accesses
This patch rpovides functional access support in Ruby. Currently only
the M5Port of RubyPort supports functional accesses. The support for
functional through the PioPort will be added as a separate patch.
Diffstat (limited to 'src')
44 files changed, 471 insertions, 186 deletions
diff --git a/src/cpu/testers/memtest/MemTest.py b/src/cpu/testers/memtest/MemTest.py index 957de8088..d5f456d69 100644 --- a/src/cpu/testers/memtest/MemTest.py +++ b/src/cpu/testers/memtest/MemTest.py @@ -50,3 +50,5 @@ class MemTest(MemObject): test = Port("Port to the memory system to test") functional = Port("Port to the functional memory used for verification") + suppress_func_warnings = Param.Bool(False, + "suppress warnings when functional accesses fail.\n") diff --git a/src/cpu/testers/memtest/memtest.cc b/src/cpu/testers/memtest/memtest.cc index d75bcb845..ef23825cd 100644 --- a/src/cpu/testers/memtest/memtest.cc +++ b/src/cpu/testers/memtest/memtest.cc @@ -146,7 +146,8 @@ MemTest::MemTest(const Params *p) percentSourceUnaligned(p->percent_source_unaligned), percentDestUnaligned(p->percent_dest_unaligned), maxLoads(p->max_loads), - atomic(p->atomic) + atomic(p->atomic), + suppress_func_warnings(p->suppress_func_warnings) { cachePort.snoopRangeSent = false; funcPort.snoopRangeSent = true; @@ -162,6 +163,7 @@ MemTest::MemTest(const Params *p) // set up counters noResponseCycles = 0; numReads = 0; + numWrites = 0; schedule(tickEvent, 0); accessRetry = false; @@ -201,9 +203,10 @@ MemTest::completeRequest(PacketPtr pkt) dmaOutstanding = false; } - DPRINTF(MemTest, "completing %s at address %x (blk %x)\n", + DPRINTF(MemTest, "completing %s at address %x (blk %x) %s\n", pkt->isWrite() ? "write" : "read", - req->getPaddr(), blockAddr(req->getPaddr())); + req->getPaddr(), blockAddr(req->getPaddr()), + pkt->isError() ? "error" : "success"); MemTestSenderState *state = dynamic_cast<MemTestSenderState *>(pkt->senderState); @@ -217,28 +220,37 @@ MemTest::completeRequest(PacketPtr pkt) assert(removeAddr != outstandingAddrs.end()); outstandingAddrs.erase(removeAddr); - if (pkt->isRead()) { - if (memcmp(pkt_data, data, pkt->getSize()) != 0) { - panic("%s: read of %x (blk %x) @ cycle %d " - "returns %x, expected %x\n", name(), - req->getPaddr(), blockAddr(req->getPaddr()), curTick(), - *pkt_data, *data); + if (pkt->isError()) { + if (!suppress_func_warnings) { + warn("Functional Access failed for %x at %x\n", + pkt->isWrite() ? "write" : "read", req->getPaddr()); } - - numReads++; - numReadsStat++; - - if (numReads == (uint64_t)nextProgressMessage) { - ccprintf(cerr, "%s: completed %d read accesses @%d\n", - name(), numReads, curTick()); - nextProgressMessage += progressInterval; - } - - if (maxLoads != 0 && numReads >= maxLoads) - exitSimLoop("maximum number of loads reached"); } else { - assert(pkt->isWrite()); - numWritesStat++; + if (pkt->isRead()) { + if (memcmp(pkt_data, data, pkt->getSize()) != 0) { + panic("%s: read of %x (blk %x) @ cycle %d " + "returns %x, expected %x\n", name(), + req->getPaddr(), blockAddr(req->getPaddr()), curTick(), + *pkt_data, *data); + } + + numReads++; + numReadsStat++; + + if (numReads == (uint64_t)nextProgressMessage) { + ccprintf(cerr, "%s: completed %d read, %d write accesses @%d\n", + name(), numReads, numWrites, curTick()); + nextProgressMessage += progressInterval; + } + + if (maxLoads != 0 && numReads >= maxLoads) + exitSimLoop("maximum number of loads reached"); + } else { + assert(pkt->isWrite()); + funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize()); + numWrites++; + numWritesStat++; + } } noResponseCycles = 0; @@ -361,6 +373,8 @@ MemTest::tick() pkt->senderState = state; if (do_functional) { + assert(pkt->needsResponse()); + pkt->setSuppressFuncError(); cachePort.sendFunctional(pkt); completeRequest(pkt); } else { @@ -392,9 +406,8 @@ MemTest::tick() MemTestSenderState *state = new MemTestSenderState(result); pkt->senderState = state; - funcPort.writeBlob(req->getPaddr(), pkt_data, req->getSize()); - if (do_functional) { + pkt->setSuppressFuncError(); cachePort.sendFunctional(pkt); completeRequest(pkt); } else { diff --git a/src/cpu/testers/memtest/memtest.hh b/src/cpu/testers/memtest/memtest.hh index 4e489de5c..292e7d83d 100644 --- a/src/cpu/testers/memtest/memtest.hh +++ b/src/cpu/testers/memtest/memtest.hh @@ -174,9 +174,11 @@ class MemTest : public MemObject Tick noResponseCycles; uint64_t numReads; + uint64_t numWrites; uint64_t maxLoads; bool atomic; + bool suppress_func_warnings; Stats::Scalar numReadsStat; Stats::Scalar numWritesStat; diff --git a/src/mem/packet.cc b/src/mem/packet.cc index 0296e7f0b..5ec977ed4 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -148,10 +148,14 @@ MemCmd::commandInfo[] = { SET2(IsResponse, IsError), InvalidCmd, "InvalidDestError" }, /* BadAddressError -- memory address invalid */ { SET2(IsResponse, IsError), InvalidCmd, "BadAddressError" }, + /* FunctionalReadError */ + { SET3(IsRead, IsResponse, IsError), InvalidCmd, "FunctionalReadError" }, + /* FunctionalWriteError */ + { SET3(IsWrite, IsResponse, IsError), InvalidCmd, "FunctionalWriteError" }, /* PrintReq */ { SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" }, /* Flush Request */ - { SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" } + { SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" }, }; bool diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 5fcd9286e..be0c20d42 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -103,6 +103,8 @@ class MemCmd NetworkNackError, // nacked at network layer (not by protocol) InvalidDestError, // packet dest field invalid BadAddressError, // memory address invalid + FunctionalReadError, // unable to fulfill functional read + FunctionalWriteError, // unable to fulfill functional write // Fake simulator-only commands PrintReq, // Print state matching address FlushReq, //request for a cache flush @@ -240,6 +242,9 @@ class Packet : public FastAlloc, public Printable /// the data pointer points to an array (thus delete []) needs to /// be called on it rather than simply delete. static const FlagsType ARRAY_DATA = 0x00004000; + /// suppress the error if this packet encounters a functional + /// access failure. + static const FlagsType SUPPRESS_FUNC_ERROR = 0x00008000; Flags flags; @@ -428,6 +433,8 @@ class Packet : public FastAlloc, public Printable void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); } void clearSupplyExclusive() { flags.clear(SUPPLY_EXCLUSIVE); } bool isSupplyExclusive() { return flags.isSet(SUPPLY_EXCLUSIVE); } + void setSuppressFuncError() { flags.set(SUPPRESS_FUNC_ERROR); } + bool suppressFuncError() { return flags.isSet(SUPPRESS_FUNC_ERROR); } // Network error conditions... encapsulate them as methods since // their encoding keeps changing (from result field to command @@ -617,6 +624,18 @@ class Packet : public FastAlloc, public Printable makeResponse(); } + void + setFunctionalResponseStatus(bool success) + { + if (!success) { + if (isWrite()) { + cmd = MemCmd::FunctionalWriteError; + } else { + cmd = MemCmd::FunctionalReadError; + } + } + } + /** * Take a request packet that has been returned as NACKED and * modify it so that it can be sent out again. Only packets that diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm index ebbd09ae0..287bda004 100644 --- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm @@ -186,17 +186,24 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") AccessPermission getAccessPermission(Address addr) { TBE tbe := L1_TBEs[addr]; if(is_valid(tbe)) { + DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState)); return L1Cache_State_to_permission(tbe.TBEState); } Entry cache_entry := getCacheEntry(addr); if(is_valid(cache_entry)) { + DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState)); return L1Cache_State_to_permission(cache_entry.CacheState); } + DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent); return AccessPermission:NotPresent; } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + void setAccessPermission(Entry cache_entry, Address addr, State state) { if (is_valid(cache_entry)) { cache_entry.changePermission(L1Cache_State_to_permission(state)); diff --git a/src/mem/protocol/MESI_CMP_directory-L2cache.sm b/src/mem/protocol/MESI_CMP_directory-L2cache.sm index 6044f5233..a8fcb07d1 100644 --- a/src/mem/protocol/MESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L2cache.sm @@ -56,7 +56,7 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") NP, AccessPermission:Invalid, desc="Not present in either cache"; SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s"; M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b"; - MT, AccessPermission:Invalid, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b"; + MT, AccessPermission:Maybe_Stale, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b"; // L2 replacement M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory"; @@ -217,17 +217,24 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") AccessPermission getAccessPermission(Address addr) { TBE tbe := L2_TBEs[addr]; if(is_valid(tbe)) { + DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState)); return L2Cache_State_to_permission(tbe.TBEState); } Entry cache_entry := getCacheEntry(addr); if(is_valid(cache_entry)) { + DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState)); return L2Cache_State_to_permission(cache_entry.CacheState); } + DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent); return AccessPermission:NotPresent; } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + void setAccessPermission(Entry cache_entry, Address addr, State state) { if (is_valid(cache_entry)) { cache_entry.changePermission(L2Cache_State_to_permission(state)); diff --git a/src/mem/protocol/MESI_CMP_directory-dir.sm b/src/mem/protocol/MESI_CMP_directory-dir.sm index 6e3e79641..423272905 100644 --- a/src/mem/protocol/MESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MESI_CMP_directory-dir.sm @@ -55,7 +55,7 @@ machine(Directory, "MESI_CMP_filter_directory protocol") ID, AccessPermission:Busy, desc="Intermediate state for DMA_READ when in I"; ID_W, AccessPermission:Busy, desc="Intermediate state for DMA_WRITE when in I"; - M, AccessPermission:Invalid, desc="memory copy may be stale, i.e. other modified copies may exist"; + M, AccessPermission:Maybe_Stale, desc="memory copy may be stale, i.e. other modified copies may exist"; IM, AccessPermission:Busy, desc="Intermediate State I>M"; MI, AccessPermission:Busy, desc="Intermediate State M>I"; M_DRD, AccessPermission:Busy, desc="Intermediate State when there is a dma read"; @@ -147,10 +147,21 @@ machine(Directory, "MESI_CMP_filter_directory protocol") AccessPermission getAccessPermission(Address addr) { TBE tbe := TBEs[addr]; if(is_valid(tbe)) { + DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(tbe.TBEState)); return Directory_State_to_permission(tbe.TBEState); } - return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + if(directory.isPresent(addr)) { + DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState)); + return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + } + + DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent); + return AccessPermission:NotPresent; + } + + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getDirectoryEntry(addr).DataBlk; } void setAccessPermission(Address addr, State state) { diff --git a/src/mem/protocol/MESI_CMP_directory-dma.sm b/src/mem/protocol/MESI_CMP_directory-dma.sm index aee2e467d..f32c73218 100644 --- a/src/mem/protocol/MESI_CMP_directory-dma.sm +++ b/src/mem/protocol/MESI_CMP_directory-dma.sm @@ -42,6 +42,10 @@ machine(DMA, "DMA Controller") void setAccessPermission(Address addr, State state) { } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + error("DMA does not support get data block."); + } + out_port(reqToDirectory_out, RequestMsg, reqToDirectory, desc="..."); in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { diff --git a/src/mem/protocol/MI_example-cache.sm b/src/mem/protocol/MI_example-cache.sm index afc415b5a..b11fddd95 100644 --- a/src/mem/protocol/MI_example-cache.sm +++ b/src/mem/protocol/MI_example-cache.sm @@ -140,6 +140,10 @@ machine(L1Cache, "MI Example L1 Cache") } } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + GenericMachineType getNondirectHitMachType(MachineID sender) { if (machineIDToMachineType(sender) == MachineType:L1Cache) { // diff --git a/src/mem/protocol/MI_example-dir.sm b/src/mem/protocol/MI_example-dir.sm index baffe2412..2bd3afa44 100644 --- a/src/mem/protocol/MI_example-dir.sm +++ b/src/mem/protocol/MI_example-dir.sm @@ -122,7 +122,11 @@ machine(Directory, "Directory protocol") return Directory_State_to_permission(tbe.TBEState); } - return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + if(directory.isPresent(addr)) { + return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + } + + return AccessPermission:NotPresent; } void setAccessPermission(Address addr, State state) { @@ -131,6 +135,10 @@ machine(Directory, "Directory protocol") } } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getDirectoryEntry(addr).DataBlk; + } + // ** OUT_PORTS ** out_port(forwardNetwork_out, RequestMsg, forwardFromDir); out_port(responseNetwork_out, ResponseMsg, responseFromDir); diff --git a/src/mem/protocol/MI_example-dma.sm b/src/mem/protocol/MI_example-dma.sm index 8d79976fc..e13d247c7 100644 --- a/src/mem/protocol/MI_example-dma.sm +++ b/src/mem/protocol/MI_example-dma.sm @@ -37,6 +37,10 @@ machine(DMA, "DMA Controller") void setAccessPermission(Address addr, State state) { } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + error("DMA Controller does not support getDataBlock function.\n"); + } + out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { diff --git a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm index 35832ee9c..2845d1ad1 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm @@ -197,14 +197,17 @@ machine(L1Cache, "Directory protocol") AccessPermission getAccessPermission(Address addr) { TBE tbe := TBEs[addr]; if(is_valid(tbe)) { + DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(tbe.TBEState)); return L1Cache_State_to_permission(tbe.TBEState); } Entry cache_entry := getCacheEntry(addr); if(is_valid(cache_entry)) { + DPRINTF(RubySlicc, "%s\n", L1Cache_State_to_permission(cache_entry.CacheState)); return L1Cache_State_to_permission(cache_entry.CacheState); } + DPRINTF(RubySlicc, "AccessPermission_NotPresent\n"); return AccessPermission:NotPresent; } @@ -214,6 +217,10 @@ machine(L1Cache, "Directory protocol") } } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + Event mandatory_request_type_to_event(RubyRequestType type) { if (type == RubyRequestType:LD) { return Event:Load; diff --git a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm index 8202a9c2f..eb9693ed9 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm @@ -56,12 +56,12 @@ machine(L2Cache, "Token protocol") // Stable states NP, AccessPermission:Invalid, desc="Not Present"; I, AccessPermission:Invalid, desc="Invalid"; - ILS, AccessPermission:Busy, desc="Idle/NP, but local sharers exist"; - ILX, AccessPermission:Busy, desc="Idle/NP, but local exclusive exists"; - ILO, AccessPermission:Busy, desc="Idle/NP, but local owner exists"; - ILOX, AccessPermission:Busy, desc="Idle/NP, but local owner exists and chip is exclusive"; - ILOS, AccessPermission:Busy, desc="Idle/NP, but local owner exists and local sharers as well"; - ILOSX, AccessPermission:Busy, desc="Idle/NP, but local owner exists, local sharers exist, chip is exclusive "; + ILS, AccessPermission:Invalid, desc="Idle/NP, but local sharers exist"; + ILX, AccessPermission:Invalid, desc="Idle/NP, but local exclusive exists"; + ILO, AccessPermission:Invalid, desc="Idle/NP, but local owner exists"; + ILOX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and chip is exclusive"; + ILOS, AccessPermission:Invalid, desc="Idle/NP, but local owner exists and local sharers as well"; + ILOSX, AccessPermission:Invalid, desc="Idle/NP, but local owner exists, local sharers exist, chip is exclusive "; S, AccessPermission:Read_Only, desc="Shared, no local sharers"; O, AccessPermission:Read_Only, desc="Owned, no local sharers"; OLS, AccessPermission:Read_Only, desc="Owned with local sharers"; @@ -502,14 +502,22 @@ machine(L2Cache, "Token protocol") AccessPermission getAccessPermission(Address addr) { TBE tbe := TBEs[addr]; if(is_valid(tbe)) { + DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState)); return L2Cache_State_to_permission(tbe.TBEState); } Entry cache_entry := getCacheEntry(addr); if(is_valid(cache_entry)) { + DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState)); 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; } @@ -519,6 +527,10 @@ machine(L2Cache, "Token protocol") } } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + MessageBuffer triggerQueue, ordered="true"; out_port(globalRequestNetwork_out, RequestMsg, GlobalRequestFromL2Cache); diff --git a/src/mem/protocol/MOESI_CMP_directory-dir.sm b/src/mem/protocol/MOESI_CMP_directory-dir.sm index b13b56ffb..b71518b3f 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm @@ -50,16 +50,16 @@ machine(Directory, "Directory protocol") // STATES state_declaration(State, desc="Directory states", default="Directory_State_I") { // Base states - I, AccessPermission:Invalid, desc="Invalid"; + I, AccessPermission:Read_Write, desc="Invalid"; S, AccessPermission:Read_Only, desc="Shared"; - O, AccessPermission:Read_Only, desc="Owner"; - M, AccessPermission:Read_Write, desc="Modified"; + O, AccessPermission:Maybe_Stale, desc="Owner"; + M, AccessPermission:Maybe_Stale, desc="Modified"; IS, AccessPermission:Busy, desc="Blocked, was in idle"; SS, AccessPermission:Read_Only, desc="Blocked, was in shared"; - OO, AccessPermission:Read_Only, desc="Blocked, was in owned"; - MO, AccessPermission:Read_Only, desc="Blocked, going to owner or maybe modified"; - MM, AccessPermission:Read_Only, desc="Blocked, going to modified"; + OO, AccessPermission:Busy, desc="Blocked, was in owned"; + MO, AccessPermission:Busy, desc="Blocked, going to owner or maybe modified"; + MM, AccessPermission:Busy, desc="Blocked, going to modified"; MM_DMA, AccessPermission:Busy, desc="Blocked, going to I"; MI, AccessPermission:Busy, desc="Blocked on a writeback"; @@ -173,9 +173,11 @@ machine(Directory, "Directory protocol") AccessPermission getAccessPermission(Address addr) { if (directory.isPresent(addr)) { + DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState)); return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); } + DPRINTF(RubySlicc, "AccessPermission_NotPresent\n"); return AccessPermission:NotPresent; } @@ -185,6 +187,10 @@ machine(Directory, "Directory protocol") } } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getDirectoryEntry(addr).DataBlk; + } + // if no sharers, then directory can be considered both a sharer and exclusive w.r.t. coherence checking bool isBlockShared(Address addr) { if (directory.isPresent(addr)) { diff --git a/src/mem/protocol/MOESI_CMP_directory-dma.sm b/src/mem/protocol/MOESI_CMP_directory-dma.sm index 0d99e354e..e3aefbe51 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dma.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dma.sm @@ -68,6 +68,10 @@ machine(DMA, "DMA Controller") void setAccessPermission(Address addr, State state) { } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + error("DMA Controller does not support getDataBlock().\n"); + } + out_port(reqToDirectory_out, RequestMsg, reqToDir, desc="..."); out_port(respToDirectory_out, ResponseMsg, respToDir, desc="..."); out_port(foo1_out, ResponseMsg, foo1, desc="..."); diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm index d557132fc..66789b594 100644 --- a/src/mem/protocol/MOESI_CMP_token-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm @@ -227,6 +227,10 @@ machine(L1Cache, "Token protocol") return L1Icache_entry; } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" { Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr)); return L1Dcache_entry; diff --git a/src/mem/protocol/MOESI_CMP_token-L2cache.sm b/src/mem/protocol/MOESI_CMP_token-L2cache.sm index c9c729263..078b5c7a6 100644 --- a/src/mem/protocol/MOESI_CMP_token-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L2cache.sm @@ -156,6 +156,10 @@ machine(L2Cache, "Token protocol") return cache_entry; } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + int getTokens(Entry cache_entry) { if (is_valid(cache_entry)) { return cache_entry.Tokens; diff --git a/src/mem/protocol/MOESI_CMP_token-dir.sm b/src/mem/protocol/MOESI_CMP_token-dir.sm index 9ca0f1fc6..9e6c6c99b 100644 --- a/src/mem/protocol/MOESI_CMP_token-dir.sm +++ b/src/mem/protocol/MOESI_CMP_token-dir.sm @@ -55,7 +55,7 @@ machine(Directory, "Token protocol") state_declaration(State, desc="Directory states", default="Directory_State_O") { // Base states O, AccessPermission:Read_Only, desc="Owner, memory has valid data, but not necessarily all the tokens"; - NO, AccessPermission:Invalid, desc="Not Owner"; + NO, AccessPermission:Maybe_Stale, desc="Not Owner"; L, AccessPermission:Busy, desc="Locked"; // Memory wait states - can block all messages including persistent requests @@ -169,6 +169,10 @@ machine(Directory, "Token protocol") return static_cast(Entry, directory[addr]); } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getDirectoryEntry(addr).DataBlk; + } + State getState(TBE tbe, Address addr) { if (is_valid(tbe)) { return tbe.TBEState; @@ -206,7 +210,13 @@ machine(Directory, "Token protocol") return Directory_State_to_permission(tbe.TBEState); } - return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + if (directory.isPresent(addr)) { + DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState)); + return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + } + + DPRINTF(RubySlicc, "AccessPermission_NotPresent\n"); + return AccessPermission:NotPresent; } void setAccessPermission(Address addr, State state) { diff --git a/src/mem/protocol/MOESI_CMP_token-dma.sm b/src/mem/protocol/MOESI_CMP_token-dma.sm index 40b60490c..98666998a 100644 --- a/src/mem/protocol/MOESI_CMP_token-dma.sm +++ b/src/mem/protocol/MOESI_CMP_token-dma.sm @@ -70,6 +70,10 @@ machine(DMA, "DMA Controller") void setAccessPermission(Address addr, State state) { } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + error("DMA Controller does not support getDataBlock function.\n"); + } + out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm index 6fe12d561..edb1587e3 100644 --- a/src/mem/protocol/MOESI_hammer-cache.sm +++ b/src/mem/protocol/MOESI_hammer-cache.sm @@ -189,6 +189,10 @@ machine(L1Cache, "AMD Hammer-like protocol") return L1Icache_entry; } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getCacheEntry(addr).DataBlk; + } + Entry getL2CacheEntry(Address address), return_by_pointer="yes" { Entry L2cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address)); return L2cache_entry; diff --git a/src/mem/protocol/MOESI_hammer-dir.sm b/src/mem/protocol/MOESI_hammer-dir.sm index 828c762cb..bb0a97ac4 100644 --- a/src/mem/protocol/MOESI_hammer-dir.sm +++ b/src/mem/protocol/MOESI_hammer-dir.sm @@ -59,38 +59,38 @@ machine(Directory, "AMD Hammer-like protocol") // STATES state_declaration(State, desc="Directory states", default="Directory_State_E") { // Base states - NX, AccessPermission:Invalid, desc="Not Owner, probe filter entry exists, block in O at Owner"; - NO, AccessPermission:Invalid, desc="Not Owner, probe filter entry exists, block in E/M at Owner"; + NX, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in O at Owner"; + NO, AccessPermission:Maybe_Stale, desc="Not Owner, probe filter entry exists, block in E/M at Owner"; S, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists pointing to the current owner"; O, AccessPermission:Read_Only, desc="Data clean, probe filter entry exists"; E, AccessPermission:Read_Write, desc="Exclusive Owner, no probe filter entry"; O_R, AccessPermission:Read_Only, desc="Was data Owner, replacing probe filter entry"; S_R, AccessPermission:Read_Only, desc="Was Not Owner or Sharer, replacing probe filter entry"; - NO_R, AccessPermission:Invalid, desc="Was Not Owner or Sharer, replacing probe filter entry"; - - NO_B, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked"; - NO_B_X, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, next queued request GETX"; - NO_B_S, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, next queued request GETS"; - NO_B_S_W, AccessPermission:Invalid, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses"; - O_B, AccessPermission:Invalid, "O^B", desc="Owner, Blocked"; - NO_B_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram"; - O_B_W, AccessPermission:Invalid, desc="Owner, Blocked, waiting for Dram"; - NO_W, AccessPermission:Invalid, desc="Not Owner, waiting for Dram"; - O_W, AccessPermission:Invalid, desc="Owner, waiting for Dram"; - NO_DW_B_W, AccessPermission:Invalid, desc="Not Owner, Dma Write waiting for Dram and cache responses"; - NO_DR_B_W, AccessPermission:Invalid, desc="Not Owner, Dma Read waiting for Dram and cache responses"; - NO_DR_B_D, AccessPermission:Invalid, desc="Not Owner, Dma Read waiting for cache responses including dirty data"; - NO_DR_B, AccessPermission:Invalid, desc="Not Owner, Dma Read waiting for cache responses"; - NO_DW_W, AccessPermission:Invalid, desc="Not Owner, Dma Write waiting for Dram"; - O_DR_B_W, AccessPermission:Invalid, desc="Owner, Dma Read waiting for Dram and cache responses"; - O_DR_B, AccessPermission:Invalid, desc="Owner, Dma Read waiting for cache responses"; - WB, AccessPermission:Invalid, desc="Blocked on a writeback"; - WB_O_W, AccessPermission:Invalid, desc="Blocked on memory write, will go to O"; - WB_E_W, AccessPermission:Invalid, desc="Blocked on memory write, will go to E"; - - NO_F, AccessPermission:Invalid, desc="Blocked on a flush"; - NO_F_W, AccessPermission:Invalid, desc="Not Owner, Blocked, waiting for Dram"; + NO_R, AccessPermission:Busy, desc="Was Not Owner or Sharer, replacing probe filter entry"; + + NO_B, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked"; + NO_B_X, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETX"; + NO_B_S, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, next queued request GETS"; + NO_B_S_W, AccessPermission:Busy, "NO^B", desc="Not Owner, Blocked, forwarded merged GETS, waiting for responses"; + O_B, AccessPermission:Busy, "O^B", desc="Owner, Blocked"; + NO_B_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram"; + O_B_W, AccessPermission:Busy, desc="Owner, Blocked, waiting for Dram"; + NO_W, AccessPermission:Busy, desc="Not Owner, waiting for Dram"; + O_W, AccessPermission:Busy, desc="Owner, waiting for Dram"; + NO_DW_B_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram and cache responses"; + NO_DR_B_W, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for Dram and cache responses"; + NO_DR_B_D, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses including dirty data"; + NO_DR_B, AccessPermission:Busy, desc="Not Owner, Dma Read waiting for cache responses"; + NO_DW_W, AccessPermission:Busy, desc="Not Owner, Dma Write waiting for Dram"; + O_DR_B_W, AccessPermission:Busy, desc="Owner, Dma Read waiting for Dram and cache responses"; + 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: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"; } // Events @@ -190,6 +190,10 @@ machine(Directory, "AMD Hammer-like protocol") return static_cast(Entry, directory[addr]); } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + return getDirectoryEntry(addr).DataBlk; + } + PfEntry getProbeFilterEntry(Address addr), return_by_pointer="yes" { if (probe_filter_enabled || full_bit_dir_enabled) { PfEntry pfEntry := static_cast(PfEntry, "pointer", probeFilter.lookup(addr)); @@ -239,7 +243,11 @@ machine(Directory, "AMD Hammer-like protocol") return Directory_State_to_permission(tbe.TBEState); } - return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + if(directory.isPresent(addr)) { + return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState); + } + + return AccessPermission:NotPresent; } void setAccessPermission(PfEntry pf_entry, Address addr, State state) { diff --git a/src/mem/protocol/MOESI_hammer-dma.sm b/src/mem/protocol/MOESI_hammer-dma.sm index f254c1633..bfb3cb98d 100644 --- a/src/mem/protocol/MOESI_hammer-dma.sm +++ b/src/mem/protocol/MOESI_hammer-dma.sm @@ -67,6 +67,10 @@ machine(DMA, "DMA Controller") void setAccessPermission(Address addr, State state) { } + DataBlock getDataBlock(Address addr), return_by_ref="yes" { + error("DMA Controller does not support getDataBlock function.\n"); + } + out_port(reqToDirectory_out, DMARequestMsg, reqToDirectory, desc="..."); in_port(dmaRequestQueue_in, SequencerMsg, mandatoryQueue, desc="...") { diff --git a/src/mem/protocol/RubySlicc_Exports.sm b/src/mem/protocol/RubySlicc_Exports.sm index ccd3aeb7f..2e4a16784 100644 --- a/src/mem/protocol/RubySlicc_Exports.sm +++ b/src/mem/protocol/RubySlicc_Exports.sm @@ -57,6 +57,13 @@ enumeration(AccessPermission, desc="...", default="AccessPermission_NotPresent") Read_Only, desc="block is Read Only (modulo functional writes)"; Read_Write, desc="block is Read/Write"; + // Possibly Invalid data + // The maybe stale permission indicates that accordingly to the protocol, + // there is no guarantee the block contains valid data. However, functional + // writes should update the block because a dataless PUT request may + // revalidate the block's data. + Maybe_Stale, desc="block can be stale or revalidated by a dataless PUT"; + // Invalid data Invalid, desc="block is in an Invalid base state"; NotPresent, desc="block is NotPresent"; diff --git a/src/mem/ruby/network/Network.cc b/src/mem/ruby/network/Network.cc index caab89715..adb90eba9 100644 --- a/src/mem/ruby/network/Network.cc +++ b/src/mem/ruby/network/Network.cc @@ -48,6 +48,7 @@ Network::Network(const Params *p) // Initialize the controller's network pointers m_topology_ptr->initNetworkPtr(this); + p->ruby_system->registerNetwork(this); } void diff --git a/src/mem/ruby/network/Network.py b/src/mem/ruby/network/Network.py index 909f2f727..9642b046e 100644 --- a/src/mem/ruby/network/Network.py +++ b/src/mem/ruby/network/Network.py @@ -48,3 +48,4 @@ class RubyNetwork(SimObject): number_of_virtual_networks = Param.Int(10, ""); topology = Param.Topology(""); control_msg_size = Param.Int(8, ""); + ruby_system = Param.RubySystem(""); diff --git a/src/mem/ruby/profiler/Profiler.cc b/src/mem/ruby/profiler/Profiler.cc index afb77f09f..08a4439db 100644 --- a/src/mem/ruby/profiler/Profiler.cc +++ b/src/mem/ruby/profiler/Profiler.cc @@ -92,6 +92,8 @@ Profiler::Profiler(const Params *p) m_inst_profiler_ptr->setHotLines(m_hot_lines); m_inst_profiler_ptr->setAllInstructions(m_all_instructions); } + + p->ruby_system->registerProfiler(this); } Profiler::~Profiler() diff --git a/src/mem/ruby/profiler/Profiler.py b/src/mem/ruby/profiler/Profiler.py index d15573aa4..3521911c2 100644 --- a/src/mem/ruby/profiler/Profiler.py +++ b/src/mem/ruby/profiler/Profiler.py @@ -36,3 +36,4 @@ class RubyProfiler(SimObject): hot_lines = Param.Bool(False, "") all_instructions = Param.Bool(False, "") num_of_sequencers = Param.Int("") + ruby_system = Param.RubySystem("") diff --git a/src/mem/ruby/recorder/Tracer.cc b/src/mem/ruby/recorder/Tracer.cc index bff59a832..fcfe5338c 100644 --- a/src/mem/ruby/recorder/Tracer.cc +++ b/src/mem/ruby/recorder/Tracer.cc @@ -40,7 +40,7 @@ Tracer::Tracer(const Params *p) m_enabled = false; m_warmup_length = p->warmup_length; assert(m_warmup_length > 0); - RubySystem::m_tracer_ptr = this; + p->ruby_system->registerTracer(this); } void diff --git a/src/mem/ruby/recorder/Tracer.py b/src/mem/ruby/recorder/Tracer.py index 7b6fd8421..7a689f9f7 100644 --- a/src/mem/ruby/recorder/Tracer.py +++ b/src/mem/ruby/recorder/Tracer.py @@ -34,3 +34,4 @@ class RubyTracer(SimObject): type = 'RubyTracer' cxx_class = 'Tracer' warmup_length = Param.Int(100000, "") + ruby_system = Param.RubySystem("") diff --git a/src/mem/ruby/slicc_interface/AbstractController.hh b/src/mem/ruby/slicc_interface/AbstractController.hh index eb8399af2..f1dac39ad 100644 --- a/src/mem/ruby/slicc_interface/AbstractController.hh +++ b/src/mem/ruby/slicc_interface/AbstractController.hh @@ -36,7 +36,9 @@ #include "mem/protocol/MachineType.hh" #include "mem/ruby/common/Address.hh" #include "mem/ruby/common/Consumer.hh" +#include "mem/ruby/common/DataBlock.hh" #include "mem/ruby/network/Network.hh" +#include "mem/ruby/system/System.hh" #include "params/RubyController.hh" #include "sim/sim_object.hh" @@ -47,7 +49,7 @@ class AbstractController : public SimObject, public Consumer { public: typedef RubyControllerParams Params; - AbstractController(const Params *p) : SimObject(p) {} + AbstractController(const Params *p); const Params *params() const { return (const Params *)_params; } // returns the number of controllers created of the specific subtype @@ -61,6 +63,8 @@ class AbstractController : public SimObject, public Consumer virtual void blockOnQueue(Address, MessageBuffer*) = 0; virtual void unblock(Address) = 0; virtual void initNetworkPtr(Network* net_ptr) = 0; + virtual AccessPermission getAccessPermission(Address addr) = 0; + virtual DataBlock& getDataBlock(Address addr) = 0; virtual void print(std::ostream & out) const = 0; virtual void printStats(std::ostream & out) const = 0; @@ -68,9 +72,6 @@ class AbstractController : public SimObject, public Consumer virtual void wakeup() = 0; // virtual void dumpStats(std::ostream & out) = 0; virtual void clearStats() = 0; - - private: - virtual AccessPermission getAccessPermission(Address addr) = 0; }; #endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCONTROLLER_HH__ diff --git a/src/mem/ruby/slicc_interface/Controller.py b/src/mem/ruby/slicc_interface/Controller.py index a5ad45145..44e08ecdc 100644 --- a/src/mem/ruby/slicc_interface/Controller.py +++ b/src/mem/ruby/slicc_interface/Controller.py @@ -41,3 +41,4 @@ class RubyController(SimObject): buffer_size = Param.Int(0, "max buffer size 0 means infinite") recycle_latency = Param.Int(10, "") number_of_TBEs = Param.Int(256, "") + ruby_system = Param.RubySystem(""); diff --git a/src/mem/ruby/slicc_interface/SConscript b/src/mem/ruby/slicc_interface/SConscript index 256f8e64e..9d4e6fe3b 100644 --- a/src/mem/ruby/slicc_interface/SConscript +++ b/src/mem/ruby/slicc_interface/SConscript @@ -35,6 +35,7 @@ if not env['RUBY']: SimObject('Controller.py') +Source('AbstractController.cc') Source('AbstractEntry.cc') Source('AbstractCacheEntry.cc') Source('RubyRequest.cc') diff --git a/src/mem/ruby/system/Cache.py b/src/mem/ruby/system/Cache.py deleted file mode 100644 index ab3ec4b29..000000000 --- a/src/mem/ruby/system/Cache.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2009 Advanced Micro Devices, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Steve Reinhardt -# Brad Beckmann - -from m5.params import * -from m5.SimObject import SimObject -from Controller import RubyController - -class RubyCache(SimObject): - type = 'RubyCache' - cxx_class = 'CacheMemory' - size = Param.MemorySize("capacity in bytes"); - latency = Param.Int(""); - assoc = Param.Int(""); - replacement_policy = Param.String("PSEUDO_LRU", ""); - start_index_bit = Param.Int(6, "index start, default 6 for 64-byte line"); diff --git a/src/mem/ruby/system/DirectoryMemory.cc b/src/mem/ruby/system/DirectoryMemory.cc index fe54c8d79..c461ce09b 100644 --- a/src/mem/ruby/system/DirectoryMemory.cc +++ b/src/mem/ruby/system/DirectoryMemory.cc @@ -156,7 +156,7 @@ DirectoryMemory::lookup(PhysAddress address) assert(isPresent(address)); Directory_Entry* entry; uint64 idx; - DPRINTF(RubyCache, "address: %s\n", address); + DPRINTF(RubyCache, "Looking up address: %s\n", address); if (m_use_map) { if (m_sparseMemory->exist(address)) { @@ -166,6 +166,7 @@ DirectoryMemory::lookup(PhysAddress address) // Note: SparseMemory internally creates a new Directory Entry m_sparseMemory->add(address); entry = m_sparseMemory->lookup(address); + entry->changePermission(AccessPermission_Read_Write); } } else { idx = mapAddressToLocalIdx(address); @@ -175,6 +176,7 @@ DirectoryMemory::lookup(PhysAddress address) if (entry == NULL) { entry = new Directory_Entry(); entry->getDataBlk().assign(m_ram->getBlockPtr(address)); + entry->changePermission(AccessPermission_Read_Only); m_entries[idx] = entry; } } diff --git a/src/mem/ruby/system/DirectoryMemory.py b/src/mem/ruby/system/DirectoryMemory.py deleted file mode 100644 index d3b6bc591..000000000 --- a/src/mem/ruby/system/DirectoryMemory.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (c) 2009 Advanced Micro Devices, Inc. -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Steve Reinhardt -# Brad Beckmann - -from m5.params import * -from m5.proxy import * -from m5.SimObject import SimObject - -class RubyDirectoryMemory(SimObject): - type = 'RubyDirectoryMemory' - cxx_class = 'DirectoryMemory' - version = Param.Int(0, "") - size = Param.MemorySize("1GB", "capacity in bytes") - use_map = Param.Bool(False, "enable sparse memory") - map_levels = Param.Int(4, "sparse memory map levels") - # the default value of the numa high bit is specified in the command line - # option and must be passed into the directory memory sim object - numa_high_bit = Param.Int("numa high bit") diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc index 40f893257..662f971f2 100644 --- a/src/mem/ruby/system/RubyPort.cc +++ b/src/mem/ruby/system/RubyPort.cc @@ -31,8 +31,8 @@ #include "arch/x86/insts/microldstop.hh" #endif // X86_ISA #include "cpu/testers/rubytest/RubyTester.hh" -#include "debug/MemoryAccess.hh" #include "debug/Ruby.hh" +#include "mem/protocol/AccessPermission.hh" #include "mem/ruby/slicc_interface/AbstractController.hh" #include "mem/ruby/system/RubyPort.hh" #include "mem/physical.hh" @@ -54,6 +54,8 @@ RubyPort::RubyPort(const Params *p) m_usingRubyTester = p->using_ruby_tester; access_phys_mem = p->access_phys_mem; + + ruby_system = p->ruby_system; } void @@ -68,7 +70,7 @@ RubyPort::getPort(const std::string &if_name, int idx) { if (if_name == "port") { return new M5Port(csprintf("%s-port%d", name(), idx), this, - access_phys_mem); + ruby_system, access_phys_mem); } if (if_name == "pio_port") { @@ -85,7 +87,7 @@ RubyPort::getPort(const std::string &if_name, int idx) assert (physMemPort == NULL); physMemPort = new M5Port(csprintf("%s-physMemPort", name()), this, - access_phys_mem); + ruby_system, access_phys_mem); return physMemPort; } @@ -109,12 +111,13 @@ RubyPort::PioPort::PioPort(const std::string &_name, ruby_port = _port; } -RubyPort::M5Port::M5Port(const std::string &_name, - RubyPort *_port, bool _access_phys_mem) +RubyPort::M5Port::M5Port(const std::string &_name, RubyPort *_port, + RubySystem *_system, bool _access_phys_mem) : SimpleTimingPort(_name, _port) { DPRINTF(RubyPort, "creating port from ruby sequcner to cpu %s\n", _name); ruby_port = _port; + ruby_system = _system; _onRetryList = false; access_phys_mem = _access_phys_mem; } @@ -289,6 +292,168 @@ RubyPort::M5Port::recvTiming(PacketPtr pkt) return false; } +bool +RubyPort::M5Port::doFunctionalRead(PacketPtr pkt) +{ + Address address(pkt->getAddr()); + Address line_address(address); + line_address.makeLineAddress(); + + AccessPermission accessPerm = AccessPermission_NotPresent; + int num_controllers = ruby_system->m_abs_cntrl_vec.size(); + + // In this loop, we try to figure which controller has a read only or + // a read write copy of the given address. Any valid copy would suffice + // for a functional read. + + DPRINTF(RubyPort, "Functional Read request for %s\n",address); + for(int i = 0;i < num_controllers;++i) + { + accessPerm = ruby_system->m_abs_cntrl_vec[i] + ->getAccessPermission(line_address); + if(accessPerm == AccessPermission_Read_Only || + accessPerm == AccessPermission_Read_Write) + { + unsigned startByte = address.getAddress() - line_address.getAddress(); + + uint8* data = pkt->getPtr<uint8_t>(true); + unsigned int size_in_bytes = pkt->getSize(); + DataBlock& block = ruby_system->m_abs_cntrl_vec[i] + ->getDataBlock(line_address); + + DPRINTF(RubyPort, "reading from %s block %s\n", + ruby_system->m_abs_cntrl_vec[i]->name(), block); + for (unsigned i = 0; i < size_in_bytes; ++i) + { + data[i] = block.getByte(i + startByte); + } + return true; + } + } + return false; +} + +bool +RubyPort::M5Port::doFunctionalWrite(PacketPtr pkt) +{ + Address addr(pkt->getAddr()); + Address line_addr = line_address(addr); + AccessPermission accessPerm = AccessPermission_NotPresent; + int num_controllers = ruby_system->m_abs_cntrl_vec.size(); + + DPRINTF(RubyPort, "Functional Write request for %s\n",addr); + + unsigned int num_ro = 0; + unsigned int num_rw = 0; + unsigned int num_busy = 0; + + // In this loop we count the number of controllers that have the given + // address in read only, read write and busy states. + for(int i = 0;i < num_controllers;++i) + { + accessPerm = ruby_system->m_abs_cntrl_vec[i]-> + getAccessPermission(line_addr); + if(accessPerm == AccessPermission_Read_Only) num_ro++; + else if(accessPerm == AccessPermission_Read_Write) num_rw++; + else if(accessPerm == AccessPermission_Busy) num_busy++; + } + + // If 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. + + DPRINTF(RubyPort, "num_busy = %d, num_ro = %d, num_rw = %d\n", + num_busy, num_ro, num_rw); + assert(num_rw <= 1); + if((num_busy == 0 && num_ro > 0) || num_rw == 1) + { + uint8* data = pkt->getPtr<uint8_t>(true); + unsigned int size_in_bytes = pkt->getSize(); + unsigned startByte = addr.getAddress() - line_addr.getAddress(); + + for(int i = 0; i < num_controllers;++i) + { + accessPerm = ruby_system->m_abs_cntrl_vec[i]-> + getAccessPermission(line_addr); + if(accessPerm == AccessPermission_Read_Only || + accessPerm == AccessPermission_Read_Write|| + accessPerm == AccessPermission_Maybe_Stale) + { + DataBlock& block = ruby_system->m_abs_cntrl_vec[i] + ->getDataBlock(line_addr); + + DPRINTF(RubyPort, "%s\n",block); + for (unsigned i = 0; i < size_in_bytes; ++i) + { + block.setByte(i + startByte, data[i]); + } + DPRINTF(RubyPort, "%s\n",block); + } + } + return true; + } + return false; +} + +void +RubyPort::M5Port::recvFunctional(PacketPtr pkt) +{ + DPRINTF(RubyPort, "Functional access caught for address %#x\n", + pkt->getAddr()); + + // Check for pio requests and directly send them to the dedicated + // pio port. + if (!isPhysMemAddress(pkt->getAddr())) { + assert(ruby_port->pio_port != NULL); + DPRINTF(RubyPort, "Request for address 0x%#x is a pio request\n", + pkt->getAddr()); + panic("RubyPort::PioPort::recvFunctional() not implemented!\n"); + } + + assert(pkt->getAddr() + pkt->getSize() <= + line_address(Address(pkt->getAddr())).getAddress() + + RubySystem::getBlockSizeBytes()); + + bool accessSucceeded = false; + bool needsResponse = pkt->needsResponse(); + + // Do the functional access on ruby memory + if (pkt->isRead()) { + accessSucceeded = doFunctionalRead(pkt); + } else if (pkt->isWrite()) { + accessSucceeded = doFunctionalWrite(pkt); + } else { + panic("RubyPort: unsupported functional command %s\n", + pkt->cmdString()); + } + + // Unless the requester explicitly said otherwise, generate an error if + // the functional request failed + if (!accessSucceeded && !pkt->suppressFuncError()) { + fatal("Ruby functional %s failed for address %#x\n", + pkt->isWrite() ? "write" : "read", pkt->getAddr()); + } + + if (access_phys_mem) { + // The attached physmem contains the official version of data. + // The following command performs the real functional access. + // This line should be removed once Ruby supplies the official version + // of data. + ruby_port->physMemPort->sendFunctional(pkt); + } + + // turn packet around to go back to requester if response expected + if (needsResponse) { + pkt->setFunctionalResponseStatus(accessSucceeded); + DPRINTF(RubyPort, "Sending packet back over port\n"); + sendFunctional(pkt); + } + DPRINTF(RubyPort, "Functional access %s!\n", + accessSucceeded ? "successful":"failed"); +} + void RubyPort::ruby_hit_callback(PacketPtr pkt) { diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh index dc7a141c3..e1ba2f7d1 100644 --- a/src/mem/ruby/system/RubyPort.hh +++ b/src/mem/ruby/system/RubyPort.hh @@ -50,12 +50,13 @@ class RubyPort : public MemObject { private: RubyPort *ruby_port; + RubySystem* ruby_system; bool _onRetryList; bool access_phys_mem; public: M5Port(const std::string &_name, RubyPort *_port, - bool _access_phys_mem); + RubySystem*_system, bool _access_phys_mem); bool sendTiming(PacketPtr pkt); void hitCallback(PacketPtr pkt); unsigned deviceBlockSize() const; @@ -69,9 +70,12 @@ class RubyPort : public MemObject protected: virtual bool recvTiming(PacketPtr pkt); virtual Tick recvAtomic(PacketPtr pkt); + virtual void recvFunctional(PacketPtr pkt); private: bool isPhysMemAddress(Addr addr); + bool doFunctionalRead(PacketPtr pkt); + bool doFunctionalWrite(PacketPtr pkt); }; friend class M5Port; @@ -145,6 +149,7 @@ class RubyPort : public MemObject M5Port* physMemPort; PhysicalMemory* physmem; + RubySystem* ruby_system; // // Based on similar code in the M5 bus. Stores pointers to those ports diff --git a/src/mem/ruby/system/RubySystem.py b/src/mem/ruby/system/RubySystem.py index 7878cec63..d66ada4b9 100644 --- a/src/mem/ruby/system/RubySystem.py +++ b/src/mem/ruby/system/RubySystem.py @@ -39,9 +39,6 @@ class RubySystem(SimObject): block_size_bytes = Param.Int(64, "default cache block size; must be a power of two"); mem_size = Param.MemorySize("total memory size of the system"); - network = Param.RubyNetwork("") - profiler = Param.RubyProfiler(""); - tracer = Param.RubyTracer(""); stats_filename = Param.String("ruby.stats", "file to which ruby dumps its stats") no_mem_vec = Param.Bool(False, "do not allocate Ruby's mem vector"); diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript index f1e7c425c..0820ef2c8 100644 --- a/src/mem/ruby/system/SConscript +++ b/src/mem/ruby/system/SConscript @@ -33,9 +33,8 @@ Import('*') if not env['RUBY']: Return() -SimObject('Cache.py') +SimObject('AbstractMemory.py') SimObject('Sequencer.py') -SimObject('DirectoryMemory.py') SimObject('MemoryControl.py') SimObject('WireBuffer.py') SimObject('RubySystem.py') diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py index 16fb795f8..5d56dc000 100644 --- a/src/mem/ruby/system/Sequencer.py +++ b/src/mem/ruby/system/Sequencer.py @@ -43,6 +43,7 @@ class RubyPort(MemObject): using_network_tester = Param.Bool(False, "") access_phys_mem = Param.Bool(True, "should the rubyport atomically update phys_mem") + ruby_system = Param.RubySystem("") class RubySequencer(RubyPort): type = 'RubySequencer' diff --git a/src/mem/ruby/system/System.cc b/src/mem/ruby/system/System.cc index d9c4fa821..81824b9b7 100644 --- a/src/mem/ruby/system/System.cc +++ b/src/mem/ruby/system/System.cc @@ -74,10 +74,6 @@ RubySystem::RubySystem(const Params *p) m_memory_size_bits = floorLog2(m_memory_size_bytes); } - m_network_ptr = p->network; - m_profiler_ptr = p->profiler; - m_tracer_ptr = p->tracer; - g_eventQueue_ptr = new RubyEventQueue(p->eventq, m_clock); g_system_ptr = this; if (p->no_mem_vec) { @@ -100,6 +96,30 @@ RubySystem::init() m_profiler_ptr->clearStats(); } +void +RubySystem::registerNetwork(Network* network_ptr) +{ + m_network_ptr = network_ptr; +} + +void +RubySystem::registerProfiler(Profiler* profiler_ptr) +{ + m_profiler_ptr = profiler_ptr; +} + +void +RubySystem::registerTracer(Tracer* tracer_ptr) +{ + m_tracer_ptr = tracer_ptr; +} + +void +RubySystem::registerAbstractController(AbstractController* cntrl) +{ + m_abs_cntrl_vec.push_back(cntrl); +} + RubySystem::~RubySystem() { delete m_network_ptr; diff --git a/src/mem/ruby/system/System.hh b/src/mem/ruby/system/System.hh index 608aca1d8..88a0186c5 100644 --- a/src/mem/ruby/system/System.hh +++ b/src/mem/ruby/system/System.hh @@ -39,9 +39,12 @@ #include "mem/ruby/common/Global.hh" #include "mem/ruby/eventqueue/RubyEventQueue.hh" #include "mem/ruby/system/RubyPort.hh" +#include "mem/ruby/slicc_interface/AbstractController.hh" #include "params/RubySystem.hh" #include "sim/sim_object.hh" +class AbstractController; +class AbstractMemory; class CacheRecorder; class MemoryVector; class Network; @@ -128,6 +131,12 @@ class RubySystem : public SimObject virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); + void registerNetwork(Network*); + void registerProfiler(Profiler*); + void registerTracer(Tracer*); + void registerAbstractMemory(AbstractMemory*); + void registerAbstractController(AbstractController*); + private: // Private copy constructor and assignment operator RubySystem(const RubySystem& obj); @@ -153,6 +162,7 @@ class RubySystem : public SimObject static Profiler* m_profiler_ptr; static Tracer* m_tracer_ptr; static MemoryVector* m_mem_vec_ptr; + std::vector<AbstractController*> m_abs_cntrl_vec; }; inline std::ostream& @@ -180,6 +190,3 @@ class RubyExitCallback : public Callback }; #endif // __MEM_RUBY_SYSTEM_SYSTEM_HH__ - - - diff --git a/src/mem/slicc/ast/MemberExprAST.py b/src/mem/slicc/ast/MemberExprAST.py index a13205252..412c178d8 100644 --- a/src/mem/slicc/ast/MemberExprAST.py +++ b/src/mem/slicc/ast/MemberExprAST.py @@ -49,10 +49,15 @@ class MemberExprAST(ExprAST): code.fix(fix) # Verify that this is a valid field name for this type - if self.field not in return_type.data_members: - self.error("Invalid object field: " + - "Type '%s' does not have data member %s" % \ - (return_type, self.field)) - - # Return the type of the field - return return_type.data_members[self.field].type + if self.field in return_type.data_members: + # Return the type of the field + return return_type.data_members[self.field].type + else: + if "interface" in return_type: + interface_type = self.symtab.find(return_type["interface"]); + if self.field in interface_type.data_members: + # Return the type of the field + return interface_type.data_members[self.field].type + self.error("Invalid object field: " + + "Type '%s' does not have data member %s" % \ + (return_type, self.field)) |