diff options
36 files changed, 2593 insertions, 1652 deletions
diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm index 50e0c3662..8744a7122 100644 --- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm @@ -36,8 +36,6 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") int l1_response_latency = 2, int to_l2_latency = 1 { - - // NODE L1 CACHE // From this node's L1 cache TO the network // a local L1 -> this L2 bank, currently ordered with directory forwarded requests @@ -135,65 +133,63 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") int cache_state_to_int(State state); int l2_select_low_bit, default="RubySystem::getBlockSizeBits()"; + void set_cache_entry(AbstractCacheEntry a); + void unset_cache_entry(); + void set_tbe(TBE a); + void unset_tbe(); + // inclusive cache returns L1 entries only - Entry getL1CacheEntry(Address addr), return_by_ref="yes" { - if (L1DcacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L1DcacheMemory[addr]); - } else { - return static_cast(Entry, L1IcacheMemory[addr]); + Entry getCacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory[addr]); + if(is_valid(L1Dcache_entry)) { + return L1Dcache_entry; } + + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory[addr]); + return L1Icache_entry; } - void changeL1Permission(Address addr, AccessPermission permission) { - if (L1DcacheMemory.isTagPresent(addr)) { - return L1DcacheMemory.changePermission(addr, permission); - } else if(L1IcacheMemory.isTagPresent(addr)) { - return L1IcacheMemory.changePermission(addr, permission); - } else { - error("cannot change permission, L1 block not present"); - } + Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory[addr]); + return L1Dcache_entry; } - bool isL1CacheTagPresent(Address addr) { - return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr)); + Entry getL1ICacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory[addr]); + return L1Icache_entry; } - State getState(Address addr) { -// if((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == true){ -// DEBUG_EXPR(id); -// DEBUG_EXPR(addr); -// } + State getState(TBE tbe, Entry cache_entry, Address addr) { assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); - if(L1_TBEs.isPresent(addr)) { - return L1_TBEs[addr].TBEState; - } else if (isL1CacheTagPresent(addr)) { - return getL1CacheEntry(addr).CacheState; + if(is_valid(tbe)) { + return tbe.TBEState; + } else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } return State:NP; } - - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); // MUST CHANGE - if(L1_TBEs.isPresent(addr)) { - L1_TBEs[addr].TBEState := state; + if(is_valid(tbe)) { + tbe.TBEState := state; } - if (isL1CacheTagPresent(addr)) { - getL1CacheEntry(addr).CacheState := state; + if (is_valid(cache_entry)) { + cache_entry.CacheState := state; // Set permission if (state == State:I) { - changeL1Permission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } else if (state == State:S || state == State:E) { - changeL1Permission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else if (state == State:M) { - changeL1Permission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else { - changeL1Permission(addr, AccessPermission:Busy); + cache_entry.changePermission(AccessPermission:Busy); } } } @@ -210,6 +206,9 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") } } + int getPendingAcks(TBE tbe) { + return tbe.pendingAcks; + } out_port(requestIntraChipL1Network_out, RequestMsg, requestFromL1Cache); out_port(responseIntraChipL1Network_out, ResponseMsg, responseFromL1Cache); @@ -220,27 +219,32 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") if (responseIntraChipL1Network_in.isReady()) { peek(responseIntraChipL1Network_in, ResponseMsg, block_on="Address") { assert(in_msg.Destination.isElement(machineID)); + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L1_TBEs[in_msg.Address]; + if(in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Data_Exclusive, in_msg.Address); + trigger(Event:Data_Exclusive, in_msg.Address, cache_entry, tbe); } else if(in_msg.Type == CoherenceResponseType:DATA) { - if ( (getState(in_msg.Address) == State:IS || getState(in_msg.Address) == State:IS_I) && - machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache ) { + if ((getState(tbe, cache_entry, in_msg.Address) == State:IS || + getState(tbe, cache_entry, in_msg.Address) == State:IS_I) && + machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) { - trigger(Event:DataS_fromL1, in_msg.Address); + trigger(Event:DataS_fromL1, in_msg.Address, cache_entry, tbe); - } else if ( (L1_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0 ) { - trigger(Event:Data_all_Acks, in_msg.Address); + } else if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) { + trigger(Event:Data_all_Acks, in_msg.Address, cache_entry, tbe); } else { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, cache_entry, tbe); } } else if (in_msg.Type == CoherenceResponseType:ACK) { - if ( (L1_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0 ) { - trigger(Event:Ack_all, in_msg.Address); + if ( (getPendingAcks(tbe) - in_msg.AckCount) == 0 ) { + trigger(Event:Ack_all, in_msg.Address, cache_entry, tbe); } else { - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, cache_entry, tbe); } } else if (in_msg.Type == CoherenceResponseType:WB_ACK) { - trigger(Event:WB_Ack, in_msg.Address); + trigger(Event:WB_Ack, in_msg.Address, cache_entry, tbe); } else { error("Invalid L1 response type"); } @@ -253,15 +257,19 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") if(requestIntraChipL1Network_in.isReady()) { peek(requestIntraChipL1Network_in, RequestMsg, block_on="Address") { assert(in_msg.Destination.isElement(machineID)); + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L1_TBEs[in_msg.Address]; + if (in_msg.Type == CoherenceRequestType:INV) { - trigger(Event:Inv, in_msg.Address); + trigger(Event:Inv, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:UPGRADE) { // upgrade transforms to GETX due to race - trigger(Event:Fwd_GETX, in_msg.Address); + trigger(Event:Fwd_GETX, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:Fwd_GETS, in_msg.Address); + trigger(Event:Fwd_GETS, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:GET_INSTR) { - trigger(Event:Fwd_GET_INSTR, in_msg.Address); + trigger(Event:Fwd_GET_INSTR, in_msg.Address, cache_entry, tbe); } else { error("Invalid forwarded request type"); } @@ -280,40 +288,55 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") // ** INSTRUCTION ACCESS *** // Check to see if it is in the OTHER L1 - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress); + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Dcache_entry, L1_TBEs[in_msg.LineAddress]); } - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 asks the L2 for it. - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, + L1Icache_entry, L1_TBEs[in_msg.LineAddress]); } else { if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, + L1Icache_entry, L1_TBEs[in_msg.LineAddress]); } else { // No room in the L1, so we need to make room in the L1 - trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress), + getL1ICacheEntry(L1IcacheMemory.cacheProbe(in_msg.LineAddress)), + L1_TBEs[L1IcacheMemory.cacheProbe(in_msg.LineAddress)]); } } } else { // *** DATA ACCESS *** - // Check to see if it is in the OTHER L1 - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress); + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Icache_entry, L1_TBEs[in_msg.LineAddress]); } - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 ask the L2 for it - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, + L1Dcache_entry, L1_TBEs[in_msg.LineAddress]); } else { if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, + L1Dcache_entry, L1_TBEs[in_msg.LineAddress]); } else { // No room in the L1, so we need to make room in the L1 - trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress), + getL1DCacheEntry(L1DcacheMemory.cacheProbe(in_msg.LineAddress)), + L1_TBEs[L1DcacheMemory.cacheProbe(in_msg.LineAddress)]); } } } @@ -395,10 +418,11 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(d_sendDataToRequestor, "d", desc="send data to requestor") { peek(requestIntraChipL1Network_in, RequestMsg) { enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; - out_msg.DataBlk := getL1CacheEntry(address).DataBlk; - out_msg.Dirty := getL1CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Response_Data; @@ -408,10 +432,11 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(d2_sendDataToL2, "d2", desc="send data to the L2 cache because of M downgrade") { enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; - out_msg.DataBlk := getL1CacheEntry(address).DataBlk; - out_msg.Dirty := getL1CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); @@ -422,10 +447,11 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(dt_sendDataToRequestor_fromTBE, "dt", desc="send data to requestor") { peek(requestIntraChipL1Network_in, RequestMsg) { enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; - out_msg.DataBlk := L1_TBEs[address].DataBlk; - out_msg.Dirty := L1_TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Response_Data; @@ -435,10 +461,11 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(d2t_sendDataToL2_fromTBE, "d2t", desc="send data to the L2 cache") { enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; - out_msg.DataBlk := L1_TBEs[address].DataBlk; - out_msg.Dirty := L1_TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); @@ -460,10 +487,11 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(f_sendDataToL2, "f", desc="send data to the L2 cache") { enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; - out_msg.DataBlk := getL1CacheEntry(address).DataBlk; - out_msg.Dirty := getL1CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); @@ -473,10 +501,11 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(ft_sendDataToL2_fromTBE, "ft", desc="send data to the L2 cache") { enqueue(responseIntraChipL1Network_out, ResponseMsg, latency=l1_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; - out_msg.DataBlk := L1_TBEs[address].DataBlk; - out_msg.Dirty := L1_TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); @@ -500,14 +529,15 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(g_issuePUTX, "g", desc="send data to the L2 cache") { enqueue(requestIntraChipL1Network_out, RequestMsg, latency=l1_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:PUTX; - out_msg.DataBlk := getL1CacheEntry(address).DataBlk; - out_msg.Dirty := getL1CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Requestor:= machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, l2_select_low_bit, l2_select_num_bits)); - if (getL1CacheEntry(address).Dirty) { + if (cache_entry.Dirty) { out_msg.MessageSize := MessageSizeType:Writeback_Data; } else { out_msg.MessageSize := MessageSizeType:Writeback_Control; @@ -541,25 +571,27 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") } } - - action(h_load_hit, "h", desc="If not prefetch, notify sequencer the load completed.") { - DPRINTF(RubySlicc, "%s\n", getL1CacheEntry(address).DataBlk); - sequencer.readCallback(address, getL1CacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); + sequencer.readCallback(address, cache_entry.DataBlk); } action(hh_store_hit, "\h", desc="If not prefetch, notify sequencer that store completed.") { - DPRINTF(RubySlicc, "%s\n", getL1CacheEntry(address).DataBlk); - sequencer.writeCallback(address, getL1CacheEntry(address).DataBlk); - getL1CacheEntry(address).Dirty := true; + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); + sequencer.writeCallback(address, cache_entry.DataBlk); + cache_entry.Dirty := true; } action(i_allocateTBE, "i", desc="Allocate TBE (isPrefetch=0, number of invalidates=0)") { check_allocate(L1_TBEs); + assert(is_valid(cache_entry)); L1_TBEs.allocate(address); - L1_TBEs[address].isPrefetch := false; - L1_TBEs[address].Dirty := getL1CacheEntry(address).Dirty; - L1_TBEs[address].DataBlk := getL1CacheEntry(address).DataBlk; + set_tbe(L1_TBEs[address]); + tbe.isPrefetch := false; + tbe.Dirty := cache_entry.Dirty; + tbe.DataBlk := cache_entry.DataBlk; } action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") { @@ -576,21 +608,24 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") action(s_deallocateTBE, "s", desc="Deallocate TBE") { L1_TBEs.deallocate(address); + unset_tbe(); } action(u_writeDataToL1Cache, "u", desc="Write data to cache") { peek(responseIntraChipL1Network_in, ResponseMsg) { - getL1CacheEntry(address).DataBlk := in_msg.DataBlk; - getL1CacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty; } } action(q_updateAckCount, "q", desc="Update ack count") { peek(responseIntraChipL1Network_in, ResponseMsg) { - L1_TBEs[address].pendingAcks := L1_TBEs[address].pendingAcks - in_msg.AckCount; + assert(is_valid(tbe)); + tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount; APPEND_TRANSITION_COMMENT(in_msg.AckCount); APPEND_TRANSITION_COMMENT(" p: "); - APPEND_TRANSITION_COMMENT(L1_TBEs[address].pendingAcks); + APPEND_TRANSITION_COMMENT(tbe.pendingAcks); } } @@ -603,17 +638,18 @@ machine(L1Cache, "MSI Directory L1 Cache CMP") } else { L1IcacheMemory.deallocate(address); } + unset_cache_entry(); } action(oo_allocateL1DCacheBlock, "\o", desc="Set L1 D-cache tag equal to tag of block B.") { - if (L1DcacheMemory.isTagPresent(address) == false) { - L1DcacheMemory.allocate(address, new Entry); + if (is_invalid(cache_entry)) { + set_cache_entry(L1DcacheMemory.allocate(address, new Entry)); } } action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") { - if (L1IcacheMemory.isTagPresent(address) == false) { - L1IcacheMemory.allocate(address, new Entry); + if (is_invalid(cache_entry)) { + set_cache_entry(L1IcacheMemory.allocate(address, new Entry)); } } diff --git a/src/mem/protocol/MESI_CMP_directory-L2cache.sm b/src/mem/protocol/MESI_CMP_directory-L2cache.sm index cc8db3335..94dd949c5 100644 --- a/src/mem/protocol/MESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MESI_CMP_directory-L2cache.sm @@ -38,7 +38,6 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") int l2_response_latency = 2, int to_l1_latency = 1 { - // L2 BANK QUEUES // From local bank of L2 cache TO the network MessageBuffer DirRequestFromL2Cache, network="To", virtual_network="0", ordered="false"; // this L2 bank -> Memory @@ -155,82 +154,80 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") TBETable L2_TBEs, template_hack="<L2Cache_TBE>"; - // inclusive cache, returns L2 entries only - Entry getL2CacheEntry(Address addr), return_by_ref="yes" { - return static_cast(Entry, L2cacheMemory[addr]); - } + void set_cache_entry(AbstractCacheEntry a); + void unset_cache_entry(); + void set_tbe(TBE a); + void unset_tbe(); - void changeL2Permission(Address addr, AccessPermission permission) { - if (L2cacheMemory.isTagPresent(addr)) { - return L2cacheMemory.changePermission(addr, permission); - } + // inclusive cache, returns L2 entries only + Entry getCacheEntry(Address addr), return_by_pointer="yes" { + return static_cast(Entry, "pointer", L2cacheMemory[addr]); } std::string getCoherenceRequestTypeStr(CoherenceRequestType type) { return CoherenceRequestType_to_string(type); } - bool isL2CacheTagPresent(Address addr) { - return (L2cacheMemory.isTagPresent(addr)); - } - - bool isOneSharerLeft(Address addr, MachineID requestor) { - assert(getL2CacheEntry(addr).Sharers.isElement(requestor)); - return (getL2CacheEntry(addr).Sharers.count() == 1); + bool isOneSharerLeft(Address addr, MachineID requestor, Entry cache_entry) { + assert(is_valid(cache_entry)); + assert(cache_entry.Sharers.isElement(requestor)); + return (cache_entry.Sharers.count() == 1); } - bool isSharer(Address addr, MachineID requestor) { - if (L2cacheMemory.isTagPresent(addr)) { - return getL2CacheEntry(addr).Sharers.isElement(requestor); + bool isSharer(Address addr, MachineID requestor, Entry cache_entry) { + if (is_valid(cache_entry)) { + return cache_entry.Sharers.isElement(requestor); } else { return false; } } - void addSharer(Address addr, MachineID requestor) { + void addSharer(Address addr, MachineID requestor, Entry cache_entry) { + assert(is_valid(cache_entry)); DPRINTF(RubySlicc, "machineID: %s, requestor: %s, address: %s\n", machineID, requestor, addr); - getL2CacheEntry(addr).Sharers.add(requestor); + cache_entry.Sharers.add(requestor); } - State getState(Address addr) { - if(L2_TBEs.isPresent(addr)) { - return L2_TBEs[addr].TBEState; - } else if (isL2CacheTagPresent(addr)) { - return getL2CacheEntry(addr).CacheState; + State getState(TBE tbe, Entry cache_entry, Address addr) { + if(is_valid(tbe)) { + return tbe.TBEState; + } else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } return State:NP; } - std::string getStateStr(Address addr) { - return L2Cache_State_to_string(getState(addr)); + std::string getStateStr(TBE tbe, Entry cache_entry, Address addr) { + return L2Cache_State_to_string(getState(tbe, cache_entry, addr)); } // when is this called - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { // MUST CHANGE - if (L2_TBEs.isPresent(addr)) { - L2_TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } - if (isL2CacheTagPresent(addr)) { - getL2CacheEntry(addr).CacheState := state; + if (is_valid(cache_entry)) { + cache_entry.CacheState := state; // Set permission if (state == State:SS ) { - changeL2Permission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else if (state == State:M) { - changeL2Permission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else if (state == State:MT) { - changeL2Permission(addr, AccessPermission:Stale); + cache_entry.changePermission(AccessPermission:Stale); } else { - changeL2Permission(addr, AccessPermission:Busy); + cache_entry.changePermission(AccessPermission:Busy); } } } - Event L1Cache_request_type_to_event(CoherenceRequestType type, Address addr, MachineID requestor) { + Event L1Cache_request_type_to_event(CoherenceRequestType type, Address addr, + MachineID requestor, Entry cache_entry) { if(type == CoherenceRequestType:GETS) { return Event:L1_GETS; } else if(type == CoherenceRequestType:GET_INSTR) { @@ -238,13 +235,13 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } else if (type == CoherenceRequestType:GETX) { return Event:L1_GETX; } else if (type == CoherenceRequestType:UPGRADE) { - if ( isL2CacheTagPresent(addr) && getL2CacheEntry(addr).Sharers.isElement(requestor) ) { + if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) { return Event:L1_UPGRADE; } else { return Event:L1_GETX; } } else if (type == CoherenceRequestType:PUTX) { - if (isSharer(addr, requestor)) { + if (isSharer(addr, requestor, cache_entry)) { return Event:L1_PUTX; } else { return Event:L1_PUTX_old; @@ -255,6 +252,15 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } } + int getPendingAcks(TBE tbe) { + return tbe.pendingAcks; + } + + bool isDirty(Entry cache_entry) { + assert(is_valid(cache_entry)); + return cache_entry.Dirty; + } + // ** OUT_PORTS ** out_port(L1RequestIntraChipL2Network_out, RequestMsg, L1RequestFromL2Cache); @@ -265,15 +271,17 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache) { if(L1unblockNetwork_in.isReady()) { peek(L1unblockNetwork_in, ResponseMsg) { + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L2_TBEs[in_msg.Address]; DPRINTF(RubySlicc, "Addr: %s State: %s Sender: %s Type: %s Dest: %s\n", - in_msg.Address, getState(in_msg.Address), in_msg.Sender, - in_msg.Type, in_msg.Destination); + in_msg.Address, getState(tbe, cache_entry, in_msg.Address), + in_msg.Sender, in_msg.Type, in_msg.Destination); assert(in_msg.Destination.isElement(machineID)); if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) { - trigger(Event:Exclusive_Unblock, in_msg.Address); + trigger(Event:Exclusive_Unblock, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) { - trigger(Event:Unblock, in_msg.Address); + trigger(Event:Unblock, in_msg.Address, cache_entry, tbe); } else { error("unknown unblock message"); } @@ -281,26 +289,27 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } } - - // Response IntraChip L2 Network - response msg to this particular L2 bank in_port(responseIntraChipL2Network_in, ResponseMsg, responseToL2Cache) { if (responseIntraChipL2Network_in.isReady()) { peek(responseIntraChipL2Network_in, ResponseMsg) { // test wether it's from a local L1 or an off chip source assert(in_msg.Destination.isElement(machineID)); + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L2_TBEs[in_msg.Address]; + if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) { if(in_msg.Type == CoherenceResponseType:DATA) { if (in_msg.Dirty) { - trigger(Event:WB_Data, in_msg.Address); + trigger(Event:WB_Data, in_msg.Address, cache_entry, tbe); } else { - trigger(Event:WB_Data_clean, in_msg.Address); + trigger(Event:WB_Data_clean, in_msg.Address, cache_entry, tbe); } } else if (in_msg.Type == CoherenceResponseType:ACK) { - if ((L2_TBEs[in_msg.Address].pendingAcks - in_msg.AckCount) == 0) { - trigger(Event:Ack_all, in_msg.Address); + if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) { + trigger(Event:Ack_all, in_msg.Address, cache_entry, tbe); } else { - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, cache_entry, tbe); } } else { error("unknown message type"); @@ -308,11 +317,14 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } else { // external message if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) { - trigger(Event:Mem_Data, in_msg.Address); // L2 now has data and all off-chip acks + // L2 now has data and all off-chip acks + trigger(Event:Mem_Data, in_msg.Address, cache_entry, tbe); } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) { - trigger(Event:Mem_Ack, in_msg.Address); // L2 now has data and all off-chip acks + // L2 now has data and all off-chip acks + trigger(Event:Mem_Ack, in_msg.Address, cache_entry, tbe); } else if(in_msg.Type == CoherenceResponseType:INV) { - trigger(Event:MEM_Inv, in_msg.Address); // L2 now has data and all off-chip acks + // L2 now has data and all off-chip acks + trigger(Event:MEM_Inv, in_msg.Address, cache_entry, tbe); } else { error("unknown message type"); } @@ -325,24 +337,36 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") in_port(L1RequestIntraChipL2Network_in, RequestMsg, L1RequestToL2Cache) { if(L1RequestIntraChipL2Network_in.isReady()) { peek(L1RequestIntraChipL2Network_in, RequestMsg) { + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L2_TBEs[in_msg.Address]; + DPRINTF(RubySlicc, "Addr: %s State: %s Req: %s Type: %s Dest: %s\n", - in_msg.Address, getState(in_msg.Address), in_msg.Requestor, - in_msg.Type, in_msg.Destination); + in_msg.Address, getState(tbe, cache_entry, in_msg.Address), + in_msg.Requestor, in_msg.Type, in_msg.Destination); + assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache); assert(in_msg.Destination.isElement(machineID)); - if (L2cacheMemory.isTagPresent(in_msg.Address)) { + + if (is_valid(cache_entry)) { // The L2 contains the block, so proceeded with handling the request - trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address, in_msg.Requestor), in_msg.Address); + trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address, + in_msg.Requestor, cache_entry), + in_msg.Address, cache_entry, tbe); } else { if (L2cacheMemory.cacheAvail(in_msg.Address)) { // L2 does't have the line, but we have space for it in the L2 - trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address, in_msg.Requestor), in_msg.Address); + trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.Address, + in_msg.Requestor, cache_entry), + in_msg.Address, cache_entry, tbe); } else { // No room in the L2, so we need to make room before handling the request - if (getL2CacheEntry( L2cacheMemory.cacheProbe(in_msg.Address) ).Dirty ) { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address)); + Entry L2cache_entry := getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address)); + if (isDirty(L2cache_entry)) { + trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address), + L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]); } else { - trigger(Event:L2_Replacement_clean, L2cacheMemory.cacheProbe(in_msg.Address)); + trigger(Event:L2_Replacement_clean, L2cacheMemory.cacheProbe(in_msg.Address), + L2cache_entry, L2_TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]); } } } @@ -368,10 +392,11 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; - out_msg.Destination.add(getL2CacheEntry(address).Exclusive); + out_msg.Destination.add(cache_entry.Exclusive); out_msg.MessageSize := MessageSizeType:Request_Control; } } @@ -379,12 +404,13 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") action(c_exclusiveReplacement, "c", desc="Send data to memory") { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:MEMORY_DATA; out_msg.Sender := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -399,33 +425,33 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } } - action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:MEMORY_DATA; out_msg.Sender := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - out_msg.Dirty := L2_TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } - action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; - out_msg.AckCount := 0 - getL2CacheEntry(address).Sharers.count(); - if (getL2CacheEntry(address).Sharers.isElement(in_msg.Requestor)) { + out_msg.AckCount := 0 - cache_entry.Sharers.count(); + if (cache_entry.Sharers.isElement(in_msg.Requestor)) { out_msg.AckCount := out_msg.AckCount + 1; } } @@ -435,16 +461,17 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; - out_msg.AckCount := 0 - getL2CacheEntry(address).Sharers.count(); - if (getL2CacheEntry(address).Sharers.isElement(in_msg.Requestor)) { + out_msg.AckCount := 0 - cache_entry.Sharers.count(); + if (cache_entry.Sharers.isElement(in_msg.Requestor)) { out_msg.AckCount := out_msg.AckCount + 1; } } @@ -454,12 +481,13 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=l2_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.AckCount := 0; } @@ -467,54 +495,59 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") { - assert(L2_TBEs[address].L1_GetS_IDs.count() > 0); + assert(is_valid(tbe)); + assert(tbe.L1_GetS_IDs.count() > 0); enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; - out_msg.Destination := L2_TBEs[address].L1_GetS_IDs; // internal nodes - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } action(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") { - assert(L2_TBEs[address].L1_GetS_IDs.count() == 1); + assert(is_valid(tbe)); + assert(tbe.L1_GetS_IDs.count() == 1); enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; - out_msg.Destination := L2_TBEs[address].L1_GetS_IDs; // internal nodes - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } - action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) { + assert(is_valid(tbe)); + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; - out_msg.Destination.add(L2_TBEs[address].L1_GetX_ID); + out_msg.Destination.add(tbe.L1_GetX_ID); DPRINTF(RubySlicc, "%s\n", out_msg.Destination); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; DPRINTF(RubySlicc, "Address: %s, Destination: %s, DataBlock: %s\n", out_msg.Address, out_msg.Destination, out_msg.DataBlk); out_msg.MessageSize := MessageSizeType:Response_Data; } } - action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") { enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := machineID; - out_msg.Destination := getL2CacheEntry(address).Sharers; + out_msg.Destination := cache_entry.Sharers; out_msg.MessageSize := MessageSizeType:Request_Control; } } @@ -522,23 +555,24 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := in_msg.Requestor; - out_msg.Destination := getL2CacheEntry(address).Sharers; + out_msg.Destination := cache_entry.Sharers; out_msg.MessageSize := MessageSizeType:Request_Control; } } } - action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(L1RequestIntraChipL2Network_out, RequestMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := in_msg.Requestor; - out_msg.Destination := getL2CacheEntry(address).Sharers; + out_msg.Destination := cache_entry.Sharers; out_msg.Destination.remove(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Request_Control; } @@ -548,11 +582,13 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") // OTHER ACTIONS action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") { check_allocate(L2_TBEs); + assert(is_valid(cache_entry)); L2_TBEs.allocate(address); - L2_TBEs[address].L1_GetS_IDs.clear(); - L2_TBEs[address].DataBlk := getL2CacheEntry(address).DataBlk; - L2_TBEs[address].Dirty := getL2CacheEntry(address).Dirty; - L2_TBEs[address].pendingAcks := getL2CacheEntry(address).Sharers.count(); + set_tbe(L2_TBEs[address]); + tbe.L1_GetS_IDs.clear(); + tbe.DataBlk := cache_entry.DataBlk; + tbe.Dirty := cache_entry.Dirty; + tbe.pendingAcks := cache_entry.Sharers.count(); } action(s_deallocateTBE, "s", desc="Deallocate external TBE") { @@ -567,56 +603,58 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") profileMsgDelay(0, L1unblockNetwork_in.dequeue_getDelayCycles()); } - action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") { profileMsgDelay(3, responseIntraChipL2Network_in.dequeue_getDelayCycles()); } - action(m_writeDataToCache, "m", desc="Write data from response queue to cache") { peek(responseIntraChipL2Network_in, ResponseMsg) { - getL2CacheEntry(address).DataBlk := in_msg.DataBlk; - getL2CacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty; } } action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - getL2CacheEntry(address).DataBlk := in_msg.DataBlk; - getL2CacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty; } } action(q_updateAck, "q", desc="update pending ack count") { peek(responseIntraChipL2Network_in, ResponseMsg) { - L2_TBEs[address].pendingAcks := L2_TBEs[address].pendingAcks - in_msg.AckCount; + assert(is_valid(tbe)); + tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount; APPEND_TRANSITION_COMMENT(in_msg.AckCount); APPEND_TRANSITION_COMMENT(" p: "); - APPEND_TRANSITION_COMMENT(L2_TBEs[address].pendingAcks); + APPEND_TRANSITION_COMMENT(tbe.pendingAcks); } } action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") { peek(responseIntraChipL2Network_in, ResponseMsg) { - L2_TBEs[address].DataBlk := in_msg.DataBlk; - L2_TBEs[address].Dirty := in_msg.Dirty; + assert(is_valid(tbe)); + tbe.DataBlk := in_msg.DataBlk; + tbe.Dirty := in_msg.Dirty; } } - action(z_stall, "z", desc="Stall") { } - action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - L2_TBEs[address].L1_GetS_IDs.add(in_msg.Requestor); + assert(is_valid(tbe)); + tbe.L1_GetS_IDs.add(in_msg.Requestor); } } action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - L2_TBEs[address].L1_GetX_ID := in_msg.Requestor; + assert(is_valid(tbe)); + tbe.L1_GetX_ID := in_msg.Requestor; } } @@ -625,13 +663,14 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") { - if (L2cacheMemory.isTagPresent(address) == false) { - L2cacheMemory.allocate(address, new Entry); + if (is_invalid(cache_entry)) { + set_cache_entry(L2cacheMemory.allocate(address, new Entry)); } } action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") { L2cacheMemory.deallocate(address); + unset_cache_entry(); } action(t_sendWBAck, "t", desc="Send writeback ACK") { @@ -649,13 +688,14 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { enqueue(responseIntraChipL2Network_out, ResponseMsg, latency=to_l1_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Response_Control; // upgrader doesn't get ack from itself, hence the + 1 - out_msg.AckCount := 0 - getL2CacheEntry(address).Sharers.count() + 1; + out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1; } } } @@ -672,47 +712,50 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") } } - - action(nn_addSharer, "\n", desc="Add L1 sharer to list") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - addSharer(address, in_msg.Requestor); - APPEND_TRANSITION_COMMENT( getL2CacheEntry(address).Sharers ); + assert(is_valid(cache_entry)); + addSharer(address, in_msg.Requestor, cache_entry); + APPEND_TRANSITION_COMMENT( cache_entry.Sharers ); } } action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") { peek(L1unblockNetwork_in, ResponseMsg) { - addSharer(address, in_msg.Sender); + assert(is_valid(cache_entry)); + addSharer(address, in_msg.Sender, cache_entry); } } - action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - getL2CacheEntry(address).Sharers.remove(in_msg.Requestor); + assert(is_valid(cache_entry)); + cache_entry.Sharers.remove(in_msg.Requestor); } } action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - getL2CacheEntry(address).Sharers.clear(); + assert(is_valid(cache_entry)); + cache_entry.Sharers.clear(); } } action(mm_markExclusive, "\m", desc="set the exclusive owner") { peek(L1RequestIntraChipL2Network_in, RequestMsg) { - getL2CacheEntry(address).Sharers.clear(); - getL2CacheEntry(address).Exclusive := in_msg.Requestor; - addSharer(address, in_msg.Requestor); + assert(is_valid(cache_entry)); + cache_entry.Sharers.clear(); + cache_entry.Exclusive := in_msg.Requestor; + addSharer(address, in_msg.Requestor, cache_entry); } } action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") { peek(L1unblockNetwork_in, ResponseMsg) { - getL2CacheEntry(address).Sharers.clear(); - getL2CacheEntry(address).Exclusive := in_msg.Sender; - addSharer(address, in_msg.Sender); + assert(is_valid(cache_entry)); + cache_entry.Sharers.clear(); + cache_entry.Exclusive := in_msg.Sender; + addSharer(address, in_msg.Sender, cache_entry); } } @@ -1060,6 +1103,3 @@ machine(L2Cache, "MESI Directory L2 Cache CMP") o_popIncomingResponseQueue; } } - - - diff --git a/src/mem/protocol/MESI_CMP_directory-dir.sm b/src/mem/protocol/MESI_CMP_directory-dir.sm index 8fa8eedc5..0c3532fbf 100644 --- a/src/mem/protocol/MESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MESI_CMP_directory-dir.sm @@ -106,14 +106,17 @@ machine(Directory, "MESI_CMP_filter_directory protocol") // ** OBJECTS ** TBETable TBEs, template_hack="<Directory_TBE>"; + + void set_tbe(TBE tbe); + void unset_tbe(); Entry getDirectoryEntry(Address addr), return_by_ref="yes" { return static_cast(Entry, directory[addr]); } - State getState(Address addr) { - if (TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; + State getState(TBE tbe, Address addr) { + if (is_valid(tbe)) { + return tbe.TBEState; } else if (directory.isPresent(addr)) { return getDirectoryEntry(addr).DirectoryState; } else { @@ -122,10 +125,10 @@ machine(Directory, "MESI_CMP_filter_directory protocol") } - void setState(Address addr, State state) { + void setState(TBE tbe, Address addr, State state) { - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } if (directory.isPresent(addr)) { @@ -161,11 +164,13 @@ machine(Directory, "MESI_CMP_filter_directory protocol") peek(requestNetwork_in, RequestMsg) { assert(in_msg.Destination.isElement(machineID)); if (isGETRequest(in_msg.Type)) { - trigger(Event:Fetch, in_msg.Address); + trigger(Event:Fetch, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:DMA_READ) { - trigger(Event:DMA_READ, makeLineAddress(in_msg.Address)); + trigger(Event:DMA_READ, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else if (in_msg.Type == CoherenceRequestType:DMA_WRITE) { - trigger(Event:DMA_WRITE, makeLineAddress(in_msg.Address)); + trigger(Event:DMA_WRITE, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else { DPRINTF(RubySlicc, "%s\n", in_msg); error("Invalid message"); @@ -179,9 +184,9 @@ machine(Directory, "MESI_CMP_filter_directory protocol") peek(responseNetwork_in, ResponseMsg) { assert(in_msg.Destination.isElement(machineID)); if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:CleanReplacement, in_msg.Address); + trigger(Event:CleanReplacement, in_msg.Address, TBEs[in_msg.Address]); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Invalid message"); @@ -195,9 +200,9 @@ machine(Directory, "MESI_CMP_filter_directory protocol") if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { - trigger(Event:Memory_Data, in_msg.Address); + trigger(Event:Memory_Data, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { - trigger(Event:Memory_Ack, in_msg.Address); + trigger(Event:Memory_Ack, in_msg.Address, TBEs[in_msg.Address]); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Invalid message"); @@ -412,15 +417,17 @@ machine(Directory, "MESI_CMP_filter_directory protocol") action(v_allocateTBE, "v", desc="Allocate TBE") { peek(requestNetwork_in, RequestMsg) { TBEs.allocate(address); - TBEs[address].DataBlk := in_msg.DataBlk; - TBEs[address].PhysicalAddress := in_msg.Address; - TBEs[address].Len := in_msg.Len; + set_tbe(TBEs[address]); + tbe.DataBlk := in_msg.DataBlk; + tbe.PhysicalAddress := in_msg.Address; + tbe.Len := in_msg.Len; } } action(dwt_writeDMADataFromTBE, "dwt", desc="DMA Write data to memory from TBE") { - //getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DataBlk, TBEs[address].Offset, TBEs[address].Len); - getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + assert(is_valid(tbe)); + //getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, tbe.Offset, tbe.Len); + getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); } @@ -429,12 +436,13 @@ machine(Directory, "MESI_CMP_filter_directory protocol") action(qw_queueMemoryWBRequest_partialTBE, "qwt", desc="Queue off-chip writeback request") { peek(responseNetwork_in, ResponseMsg) { enqueue(memQueue_out, MemoryMsg, latency=to_mem_ctrl_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; out_msg.OriginalRequestorMachId := in_msg.Sender; //out_msg.DataBlk := in_msg.DataBlk; - //out_msg.DataBlk.copyPartial(TBEs[address].DataBlk, TBEs[address].Offset, TBEs[address].Len); - out_msg.DataBlk.copyPartial(TBEs[address].DataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + //out_msg.DataBlk.copyPartial(tbe.DataBlk, tbe.Offset, tbe.Len); + out_msg.DataBlk.copyPartial(tbe.DataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); out_msg.MessageSize := in_msg.MessageSize; //out_msg.Prefetch := in_msg.Prefetch; @@ -446,6 +454,7 @@ machine(Directory, "MESI_CMP_filter_directory protocol") action(w_deallocateTBE, "w", desc="Deallocate TBE") { TBEs.deallocate(address); + unset_tbe(); } diff --git a/src/mem/protocol/MI_example-cache.sm b/src/mem/protocol/MI_example-cache.sm index 8232e93e1..96b7ab826 100644 --- a/src/mem/protocol/MI_example-cache.sm +++ b/src/mem/protocol/MI_example-cache.sm @@ -73,7 +73,15 @@ machine(L1Cache, "MI Example L1 Cache") TBETable TBEs, template_hack="<L1Cache_TBE>"; + // PROTOTYPES + void set_cache_entry(AbstractCacheEntry a); + void unset_cache_entry(); + void set_tbe(TBE b); + void unset_tbe(); + Entry getCacheEntry(Address address), return_by_pointer="yes" { + return static_cast(Entry, "pointer", cacheMemory.lookup(address)); + } // FUNCTIONS Event mandatory_request_type_to_event(CacheRequestType type) { @@ -88,35 +96,31 @@ machine(L1Cache, "MI Example L1 Cache") } } - Entry getCacheEntry(Address addr), return_by_ref="yes" { - return static_cast(Entry, cacheMemory[addr]); - } - - State getState(Address addr) { + State getState(TBE tbe, Entry cache_entry, Address addr) { - if (TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; + if (is_valid(tbe)) { + return tbe.TBEState; } - else if (cacheMemory.isTagPresent(addr)) { - return getCacheEntry(addr).CacheState; + else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } else { return State:I; } } - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } - if (cacheMemory.isTagPresent(addr)) { - getCacheEntry(addr).CacheState := state; + if (is_valid(cache_entry)) { + cache_entry.CacheState := state; if (state == State:M) { - cacheMemory.changePermission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else { - cacheMemory.changePermission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } } } @@ -141,17 +145,21 @@ machine(L1Cache, "MI Example L1 Cache") in_port(forwardRequestNetwork_in, RequestMsg, forwardToCache) { if (forwardRequestNetwork_in.isReady()) { peek(forwardRequestNetwork_in, RequestMsg, block_on="Address") { + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; + if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:Fwd_GETX, in_msg.Address); + trigger(Event:Fwd_GETX, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:WB_ACK) { - trigger(Event:Writeback_Ack, in_msg.Address); + trigger(Event:Writeback_Ack, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:WB_NACK) { - trigger(Event:Writeback_Nack, in_msg.Address); + trigger(Event:Writeback_Nack, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:INV) { - trigger(Event:Inv, in_msg.Address); + trigger(Event:Inv, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); @@ -163,8 +171,12 @@ machine(L1Cache, "MI Example L1 Cache") in_port(responseNetwork_in, ResponseMsg, responseToCache) { if (responseNetwork_in.isReady()) { peek(responseNetwork_in, ResponseMsg, block_on="Address") { + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; + if (in_msg.Type == CoherenceResponseType:DATA) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); @@ -178,14 +190,17 @@ machine(L1Cache, "MI Example L1 Cache") if (mandatoryQueue_in.isReady()) { peek(mandatoryQueue_in, CacheMsg, block_on="LineAddress") { - - if (cacheMemory.isTagPresent(in_msg.LineAddress) == false && + Entry cache_entry := getCacheEntry(in_msg.LineAddress); + if (is_invalid(cache_entry) && cacheMemory.cacheAvail(in_msg.LineAddress) == false ) { // make room for the block - trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:Replacement, cacheMemory.cacheProbe(in_msg.LineAddress), + getCacheEntry(cacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[cacheMemory.cacheProbe(in_msg.LineAddress)]); } else { - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress, + cache_entry, TBEs[in_msg.LineAddress]); } } } @@ -205,11 +220,12 @@ machine(L1Cache, "MI Example L1 Cache") action(b_issuePUT, "b", desc="Issue a PUT request") { enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:PUTX; out_msg.Requestor := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.DataBlk := getCacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.MessageSize := MessageSizeType:Data; } } @@ -218,11 +234,12 @@ machine(L1Cache, "MI Example L1 Cache") action(e_sendData, "e", desc="Send data from cache to requestor") { peek(forwardRequestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getCacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -231,26 +248,28 @@ machine(L1Cache, "MI Example L1 Cache") action(ee_sendDataFromTBE, "\e", desc="Send data from TBE to requestor") { peek(forwardRequestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Data; } } } - action(i_allocateL1CacheBlock, "i", desc="Allocate a cache block") { - if (cacheMemory.isTagPresent(address) == false) { - cacheMemory.allocate(address, new Entry); + if (is_valid(cache_entry)) { + } else { + set_cache_entry(cacheMemory.allocate(address, new Entry)); } } action(h_deallocateL1CacheBlock, "h", desc="deallocate a cache block") { - if (cacheMemory.isTagPresent(address) == true) { + if (is_valid(cache_entry)) { cacheMemory.deallocate(address); + unset_cache_entry(); } } @@ -273,55 +292,64 @@ machine(L1Cache, "MI Example L1 Cache") } action(r_load_hit, "r", desc="Notify sequencer the load completed.") { - DPRINTF(RubySlicc,"%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk); sequencer.readCallback(address, GenericMachineType:L1Cache, - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } action(rx_load_hit, "rx", desc="External load completed.") { peek(responseNetwork_in, ResponseMsg) { - DPRINTF(RubySlicc,"%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk); sequencer.readCallback(address, getNondirectHitMachType(in_msg.Sender), - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } } action(s_store_hit, "s", desc="Notify sequencer that store completed.") { - DPRINTF(RubySlicc,"%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk); sequencer.writeCallback(address, GenericMachineType:L1Cache, - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } action(sx_store_hit, "sx", desc="External store completed.") { peek(responseNetwork_in, ResponseMsg) { - DPRINTF(RubySlicc,"%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk); sequencer.writeCallback(address, getNondirectHitMachType(in_msg.Sender), - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } } action(u_writeDataToCache, "u", desc="Write data to the cache") { peek(responseNetwork_in, ResponseMsg) { - getCacheEntry(address).DataBlk := in_msg.DataBlk; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; } } action(v_allocateTBE, "v", desc="Allocate TBE") { TBEs.allocate(address); + set_tbe(TBEs[address]); } action(w_deallocateTBE, "w", desc="Deallocate TBE") { TBEs.deallocate(address); + unset_tbe(); } action(x_copyDataFromCacheToTBE, "x", desc="Copy data from cache to TBE") { - TBEs[address].DataBlk := getCacheEntry(address).DataBlk; + assert(is_valid(cache_entry)); + assert(is_valid(tbe)); + tbe.DataBlk := cache_entry.DataBlk; } action(z_stall, "z", desc="stall") { diff --git a/src/mem/protocol/MI_example-dir.sm b/src/mem/protocol/MI_example-dir.sm index dfb95aedd..30720e433 100644 --- a/src/mem/protocol/MI_example-dir.sm +++ b/src/mem/protocol/MI_example-dir.sm @@ -76,13 +76,16 @@ machine(Directory, "Directory protocol") // ** OBJECTS ** TBETable TBEs, template_hack="<Directory_TBE>"; + void set_tbe(TBE b); + void unset_tbe(); + Entry getDirectoryEntry(Address addr), return_by_ref="yes" { return static_cast(Entry, directory[addr]); } - State getState(Address addr) { - if (TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; + State getState(TBE tbe, Address addr) { + if (is_valid(tbe)) { + return tbe.TBEState; } else if (directory.isPresent(addr)) { return getDirectoryEntry(addr).DirectoryState; } else { @@ -90,10 +93,10 @@ machine(Directory, "Directory protocol") } } - void setState(Address addr, State state) { + void setState(TBE tbe, Address addr, State state) { - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } if (directory.isPresent(addr)) { @@ -126,10 +129,11 @@ machine(Directory, "Directory protocol") in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir) { if (dmaRequestQueue_in.isReady()) { peek(dmaRequestQueue_in, DMARequestMsg) { + TBE tbe := TBEs[in_msg.LineAddress]; if (in_msg.Type == DMARequestType:READ) { - trigger(Event:DMA_READ, in_msg.LineAddress); + trigger(Event:DMA_READ, in_msg.LineAddress, tbe); } else if (in_msg.Type == DMARequestType:WRITE) { - trigger(Event:DMA_WRITE, in_msg.LineAddress); + trigger(Event:DMA_WRITE, in_msg.LineAddress, tbe); } else { error("Invalid message"); } @@ -140,15 +144,16 @@ machine(Directory, "Directory protocol") in_port(requestQueue_in, RequestMsg, requestToDir) { if (requestQueue_in.isReady()) { peek(requestQueue_in, RequestMsg) { + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:GETS, in_msg.Address); + trigger(Event:GETS, in_msg.Address, tbe); } else if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:GETX, in_msg.Address); + trigger(Event:GETX, in_msg.Address, tbe); } else if (in_msg.Type == CoherenceRequestType:PUTX) { if (getDirectoryEntry(in_msg.Address).Owner.isElement(in_msg.Requestor)) { - trigger(Event:PUTX, in_msg.Address); + trigger(Event:PUTX, in_msg.Address, tbe); } else { - trigger(Event:PUTX_NotOwner, in_msg.Address); + trigger(Event:PUTX_NotOwner, in_msg.Address, tbe); } } else { error("Invalid message"); @@ -162,10 +167,11 @@ machine(Directory, "Directory protocol") in_port(memQueue_in, MemoryMsg, memBuffer) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == MemoryRequestType:MEMORY_READ) { - trigger(Event:Memory_Data, in_msg.Address); + trigger(Event:Memory_Data, in_msg.Address, tbe); } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { - trigger(Event:Memory_Ack, in_msg.Address); + trigger(Event:Memory_Ack, in_msg.Address, tbe); } else { DPRINTF(RubySlicc,"%s\n", in_msg.Type); error("Invalid message"); @@ -232,11 +238,12 @@ machine(Directory, "Directory protocol") action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") { peek(memQueue_in, MemoryMsg) { enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:DATA; out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -247,11 +254,12 @@ machine(Directory, "Directory protocol") action(drp_sendDMAData, "drp", desc="Send Data to DMA controller from incoming PUTX") { peek(requestQueue_in, RequestMsg) { enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:DATA; out_msg.DataBlk := in_msg.DataBlk; // we send the entire data block and rely on the dma controller to split it up if need be - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -259,10 +267,11 @@ machine(Directory, "Directory protocol") action(da_sendDMAAck, "da", desc="Send Ack to DMA controller") { enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:ACK; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Writeback_Control; } } @@ -320,35 +329,40 @@ machine(Directory, "Directory protocol") } action(dwt_writeDMADataFromTBE, "dwt", desc="DMA Write data to memory from TBE") { - getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + assert(is_valid(tbe)); + getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); } action(v_allocateTBE, "v", desc="Allocate TBE") { peek(dmaRequestQueue_in, DMARequestMsg) { TBEs.allocate(address); - TBEs[address].DataBlk := in_msg.DataBlk; - TBEs[address].PhysicalAddress := in_msg.PhysicalAddress; - TBEs[address].Len := in_msg.Len; - TBEs[address].DmaRequestor := in_msg.Requestor; + set_tbe(TBEs[address]); + tbe.DataBlk := in_msg.DataBlk; + tbe.PhysicalAddress := in_msg.PhysicalAddress; + tbe.Len := in_msg.Len; + tbe.DmaRequestor := in_msg.Requestor; } } action(r_allocateTbeForDmaRead, "\r", desc="Allocate TBE for DMA Read") { peek(dmaRequestQueue_in, DMARequestMsg) { TBEs.allocate(address); - TBEs[address].DmaRequestor := in_msg.Requestor; + set_tbe(TBEs[address]); + tbe.DmaRequestor := in_msg.Requestor; } } action(v_allocateTBEFromRequestNet, "\v", desc="Allocate TBE") { peek(requestQueue_in, RequestMsg) { TBEs.allocate(address); - TBEs[address].DataBlk := in_msg.DataBlk; + set_tbe(TBEs[address]); + tbe.DataBlk := in_msg.DataBlk; } } action(w_deallocateTBE, "w", desc="Deallocate TBE") { TBEs.deallocate(address); + unset_tbe(); } action(z_recycleRequestQueue, "z", desc="recycle request queue") { @@ -407,12 +421,13 @@ machine(Directory, "Directory protocol") action(qw_queueMemoryWBRequest_partialTBE, "qwt", desc="Queue off-chip writeback request") { peek(requestQueue_in, RequestMsg) { enqueue(memQueue_out, MemoryMsg, latency="1") { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; out_msg.OriginalRequestorMachId := in_msg.Requestor; // get incoming data // out_msg.DataBlk := in_msg.DataBlk; - out_msg.DataBlk.copyPartial(TBEs[address].DataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + out_msg.DataBlk.copyPartial(tbe.DataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); out_msg.MessageSize := in_msg.MessageSize; //out_msg.Prefetch := in_msg.Prefetch; @@ -445,9 +460,10 @@ machine(Directory, "Directory protocol") action(w_writeDataToMemoryFromTBE, "\w", desc="Write date to directory memory from TBE") { //getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk; - getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DataBlk, - addressOffset(TBEs[address].PhysicalAddress), - TBEs[address].Len); + assert(is_valid(tbe)); + getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, + addressOffset(tbe.PhysicalAddress), + tbe.Len); } diff --git a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm index 31de269a9..4082f23c9 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm @@ -136,6 +136,10 @@ machine(L1Cache, "Directory protocol") bool isPresent(Address); } + void set_cache_entry(AbstractCacheEntry b); + void unset_cache_entry(); + void set_tbe(TBE b); + void unset_tbe(); MessageBuffer mandatoryQueue, ordered="false", abstract_chip_ptr="true"; @@ -143,102 +147,69 @@ machine(L1Cache, "Directory protocol") TimerTable useTimerTable; int l2_select_low_bit, default="RubySystem::getBlockSizeBits()"; - Entry getCacheEntry(Address addr), return_by_ref="yes" { - if (L1DcacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L1DcacheMemory[addr]); - } else { - return static_cast(Entry, L1IcacheMemory[addr]); + Entry getCacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr)); + if(is_valid(L1Dcache_entry)) { + return L1Dcache_entry; } - } - void changePermission(Address addr, AccessPermission permission) { - if (L1DcacheMemory.isTagPresent(addr)) { - return L1DcacheMemory.changePermission(addr, permission); - } else { - return L1IcacheMemory.changePermission(addr, permission); - } + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory.lookup(addr)); + return L1Icache_entry; } - bool isCacheTagPresent(Address addr) { - return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr)); + Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" { + return static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr)); } - State getState(Address addr) { - assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); + Entry getL1ICacheEntry(Address addr), return_by_pointer="yes" { + return static_cast(Entry, "pointer", L1IcacheMemory.lookup(addr)); + } - if(TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; - } else if (isCacheTagPresent(addr)) { - return getCacheEntry(addr).CacheState; + State getState(TBE tbe, Entry cache_entry, Address addr) { + if(is_valid(tbe)) { + return tbe.TBEState; + } else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } return State:I; } - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } - if (isCacheTagPresent(addr)) { - if ( ((getCacheEntry(addr).CacheState != State:M) && (state == State:M)) || - ((getCacheEntry(addr).CacheState != State:MM) && (state == State:MM)) || - ((getCacheEntry(addr).CacheState != State:S) && (state == State:S)) || - ((getCacheEntry(addr).CacheState != State:O) && (state == State:O)) ) { + if (is_valid(cache_entry)) { + if ( ((cache_entry.CacheState != State:M) && (state == State:M)) || + ((cache_entry.CacheState != State:MM) && (state == State:MM)) || + ((cache_entry.CacheState != State:S) && (state == State:S)) || + ((cache_entry.CacheState != State:O) && (state == State:O)) ) { - getCacheEntry(addr).CacheState := state; + cache_entry.CacheState := state; sequencer.checkCoherence(addr); } else { - getCacheEntry(addr).CacheState := state; + cache_entry.CacheState := state; } // Set permission if (state == State:MM || state == State:MM_W) { - changePermission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else if ((state == State:S) || (state == State:O) || (state == State:M) || (state == State:M_W) || (state == State:SM) || (state == State:OM)) { - changePermission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else { - changePermission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } } } - bool isBlockExclusive(Address addr) { - - if (isCacheTagPresent(addr)) { - if ( (getCacheEntry(addr).CacheState == State:M) || (getCacheEntry(addr).CacheState == State:MM) - || (getCacheEntry(addr).CacheState == State:MI) || (getCacheEntry(addr).CacheState == State:MM_W) - ) { - return true; - } - } - - return false; - } - - bool isBlockShared(Address addr) { - if (isCacheTagPresent(addr)) { - if ( (getCacheEntry(addr).CacheState == State:S) || (getCacheEntry(addr).CacheState == State:O) - || (getCacheEntry(addr).CacheState == State:SM) - || (getCacheEntry(addr).CacheState == State:OI) - || (getCacheEntry(addr).CacheState == State:SI) - || (getCacheEntry(addr).CacheState == State:OM) - ) { - return true; - } - } - - return false; - } - - Event mandatory_request_type_to_event(CacheRequestType type) { if (type == CacheRequestType:LD) { return Event:Load; @@ -265,7 +236,9 @@ machine(L1Cache, "Directory protocol") // Use Timer in_port(useTimerTable_in, Address, useTimerTable) { if (useTimerTable_in.isReady()) { - trigger(Event:Use_Timeout, useTimerTable.readyAddress()); + trigger(Event:Use_Timeout, useTimerTable.readyAddress(), + getCacheEntry(useTimerTable.readyAddress()), + TBEs[useTimerTable.readyAddress()]); } } @@ -283,7 +256,8 @@ machine(L1Cache, "Directory protocol") if (triggerQueue_in.isReady()) { peek(triggerQueue_in, TriggerMsg) { if (in_msg.Type == TriggerType:ALL_ACKS) { - trigger(Event:All_acks, in_msg.Address); + trigger(Event:All_acks, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { error("Unexpected message"); } @@ -299,24 +273,33 @@ machine(L1Cache, "Directory protocol") peek(requestNetwork_in, RequestMsg, block_on="Address") { assert(in_msg.Destination.isElement(machineID)); DPRINTF(RubySlicc, "L1 received: %s\n", in_msg.Type); -if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:DMA_WRITE) { + + if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:DMA_WRITE) { if (in_msg.Requestor == machineID && in_msg.RequestorMachine == MachineType:L1Cache) { - trigger(Event:Own_GETX, in_msg.Address); + trigger(Event:Own_GETX, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { - trigger(Event:Fwd_GETX, in_msg.Address); + trigger(Event:Fwd_GETX, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } } else if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:Fwd_GETS, in_msg.Address); + trigger(Event:Fwd_GETS, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:DMA_READ) { - trigger(Event:Fwd_DMA, in_msg.Address); + trigger(Event:Fwd_DMA, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:WB_ACK) { - trigger(Event:Writeback_Ack, in_msg.Address); + trigger(Event:Writeback_Ack, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:WB_ACK_DATA) { - trigger(Event:Writeback_Ack_Data, in_msg.Address); + trigger(Event:Writeback_Ack_Data, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:WB_NACK) { - trigger(Event:Writeback_Nack, in_msg.Address); + trigger(Event:Writeback_Nack, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:INV) { - trigger(Event:Inv, in_msg.Address); + trigger(Event:Inv, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { error("Unexpected message"); } @@ -329,11 +312,14 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT if (responseToL1Cache_in.isReady()) { peek(responseToL1Cache_in, ResponseMsg, block_on="Address") { if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:DATA) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Exclusive_Data, in_msg.Address); + trigger(Event:Exclusive_Data, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { error("Unexpected message"); } @@ -352,41 +338,63 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); // Check to see if it is in the OTHER L1 - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + if (is_valid(L1Dcache_entry)) { // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress); + trigger(Event:L1_Replacement, in_msg.LineAddress, L1Dcache_entry, + TBEs[in_msg.LineAddress]); } - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 asks the L2 for it. - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Icache_entry, + TBEs[in_msg.LineAddress]); } else { if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 so let's see if the L2 has it - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Icache_entry, + TBEs[in_msg.LineAddress]); } else { // No room in the L1, so we need to make room in the L1 - trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_Replacement, + L1IcacheMemory.cacheProbe(in_msg.LineAddress), + getL1ICacheEntry(L1IcacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L1IcacheMemory.cacheProbe(in_msg.LineAddress)]); } } } else { // *** DATA ACCESS *** + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); // Check to see if it is in the OTHER L1 - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + if (is_valid(L1Icache_entry)) { // The block is in the wrong L1, put the request on the queue to the shared L2 - trigger(Event:L1_Replacement, in_msg.LineAddress); + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Icache_entry, TBEs[in_msg.LineAddress]); } - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 ask the L2 for it - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Dcache_entry, + TBEs[in_msg.LineAddress]); } else { if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 let's see if the L2 has it - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Dcache_entry, + TBEs[in_msg.LineAddress]); } else { // No room in the L1, so we need to make room in the L1 - trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_Replacement, + L1DcacheMemory.cacheProbe(in_msg.LineAddress), + getL1DCacheEntry(L1DcacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L1DcacheMemory.cacheProbe(in_msg.LineAddress)]); } } } @@ -404,7 +412,7 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceRequestType:GETS; out_msg.Requestor := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Request_Control; out_msg.AccessMode := in_msg.AccessMode; out_msg.Prefetch := in_msg.Prefetch; @@ -418,8 +426,9 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Address := address; out_msg.Type := CoherenceRequestType:GETX; out_msg.Requestor := machineID; + out_msg.RequestorMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Request_Control; out_msg.AccessMode := in_msg.AccessMode; out_msg.Prefetch := in_msg.Prefetch; @@ -433,8 +442,9 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Address := address; out_msg.Type := CoherenceRequestType:PUTX; out_msg.Requestor := machineID; + out_msg.RequestorMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Writeback_Control; } } @@ -446,7 +456,7 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceRequestType:PUTO; out_msg.Requestor := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Writeback_Control; } } @@ -458,22 +468,23 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceRequestType:PUTS; out_msg.Requestor := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Writeback_Control; } } action(e_sendData, "e", desc="Send data from cache to requestor") { peek(requestNetwork_in, RequestMsg) { + assert(is_valid(cache_entry)); if (in_msg.RequestorMachine == MachineType:L2Cache) { enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // out_msg.Dirty := getCacheEntry(address).Dirty; + l2_select_low_bit, l2_select_num_bits)); + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; out_msg.Dirty := false; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:Response_Data; @@ -486,8 +497,8 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; out_msg.Dirty := false; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; @@ -499,13 +510,14 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT action(e_sendDataToL2, "ee", desc="Send data from cache to requestor") { enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + l2_select_low_bit, l2_select_num_bits)); + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Acks := 0; // irrelevant out_msg.MessageSize := MessageSizeType:Response_Data; } @@ -514,6 +526,7 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT action(ee_sendDataExclusive, "\e", desc="Send data from cache to requestor, don't keep a shared copy") { peek(requestNetwork_in, RequestMsg) { + assert(is_valid(cache_entry)); if (in_msg.RequestorMachine == MachineType:L2Cache) { enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) { out_msg.Address := address; @@ -521,9 +534,9 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + l2_select_low_bit, l2_select_num_bits)); + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:Response_Data; } @@ -536,8 +549,8 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; } @@ -566,7 +579,7 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.Acks := 0 - 1; // -1 out_msg.MessageSize := MessageSizeType:Response_Control; } @@ -580,7 +593,7 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceResponseType:UNBLOCK; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Unblock_Control; } } @@ -590,28 +603,33 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Address := address; out_msg.Type := CoherenceResponseType:UNBLOCK_EXCLUSIVE; out_msg.Sender := machineID; + out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); + l2_select_low_bit, l2_select_num_bits)); out_msg.MessageSize := MessageSizeType:Unblock_Control; } } action(h_load_hit, "h", desc="Notify sequencer the load completed.") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); - sequencer.readCallback(address, getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); + sequencer.readCallback(address, cache_entry.DataBlk); } action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); - sequencer.writeCallback(address, getCacheEntry(address).DataBlk); - getCacheEntry(address).Dirty := true; + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); + sequencer.writeCallback(address, cache_entry.DataBlk); + cache_entry.Dirty := true; } action(i_allocateTBE, "i", desc="Allocate TBE") { check_allocate(TBEs); TBEs.allocate(address); - TBEs[address].DataBlk := getCacheEntry(address).DataBlk; // Data only used for writebacks - TBEs[address].Dirty := getCacheEntry(address).Dirty; + set_tbe(TBEs[address]); + assert(is_valid(cache_entry)); + tbe.DataBlk := cache_entry.DataBlk; // Data only used for writebacks + tbe.Dirty := cache_entry.Dirty; } action(j_popTriggerQueue, "j", desc="Pop trigger queue.") { @@ -632,14 +650,16 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") { peek(responseToL1Cache_in, ResponseMsg) { + assert(is_valid(tbe)); DPRINTF(RubySlicc, "L1 decrementNumberOfMessages: %d\n", in_msg.Acks); - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks; + tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks; } } action(mm_decrementNumberOfMessages, "\m", desc="Decrement the number of messages for which we're waiting") { peek(requestNetwork_in, RequestMsg) { - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks; + assert(is_valid(tbe)); + tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks; } } @@ -648,7 +668,8 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT } action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") { - if (TBEs[address].NumPendingMsgs == 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; out_msg.Type := TriggerType:ALL_ACKS; @@ -663,14 +684,15 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") { peek(requestNetwork_in, RequestMsg) { + assert(is_valid(tbe)); if (in_msg.RequestorMachine == MachineType:L1Cache) { enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := TBEs[address].DataBlk; - // out_msg.Dirty := TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + // out_msg.Dirty := tbe.Dirty; out_msg.Dirty := false; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; @@ -682,9 +704,9 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); - out_msg.DataBlk := TBEs[address].DataBlk; - // out_msg.Dirty := TBEs[address].Dirty; + l2_select_low_bit, l2_select_num_bits)); + out_msg.DataBlk := tbe.DataBlk; + // out_msg.Dirty := tbe.Dirty; out_msg.Dirty := false; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:Response_Data; @@ -695,14 +717,15 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT action(q_sendExclusiveDataFromTBEToCache, "qq", desc="Send data from TBE to cache") { peek(requestNetwork_in, RequestMsg) { + assert(is_valid(tbe)); if (in_msg.RequestorMachine == MachineType:L1Cache) { enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := TBEs[address].DataBlk; - out_msg.Dirty := TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; } @@ -713,9 +736,9 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); - out_msg.DataBlk := TBEs[address].DataBlk; - out_msg.Dirty := TBEs[address].Dirty; + l2_select_low_bit, l2_select_num_bits)); + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.Acks := in_msg.Acks; out_msg.MessageSize := MessageSizeType:Response_Data; } @@ -727,30 +750,33 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT // L2 will usually request data for a writeback action(qq_sendWBDataFromTBEToL2, "\q", desc="Send data from TBE to L2") { enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L1Cache; out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache, - l2_select_low_bit, l2_select_num_bits)); - out_msg.Dirty := TBEs[address].Dirty; - if (TBEs[address].Dirty) { + l2_select_low_bit, l2_select_num_bits)); + out_msg.Dirty := tbe.Dirty; + if (tbe.Dirty) { out_msg.Type := CoherenceResponseType:WRITEBACK_DIRTY_DATA; } else { out_msg.Type := CoherenceResponseType:WRITEBACK_CLEAN_DATA; } - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Data; } } action(s_deallocateTBE, "s", desc="Deallocate TBE") { TBEs.deallocate(address); + unset_tbe(); } action(u_writeDataToCache, "u", desc="Write data to cache") { peek(responseToL1Cache_in, ResponseMsg) { - getCacheEntry(address).DataBlk := in_msg.DataBlk; - getCacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty; if (in_msg.Type == CoherenceResponseType:DATA) { //assert(in_msg.Dirty == false); @@ -761,9 +787,10 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") { peek(responseToL1Cache_in, ResponseMsg) { - assert(getCacheEntry(address).DataBlk == in_msg.DataBlk); - getCacheEntry(address).DataBlk := in_msg.DataBlk; - getCacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + assert(cache_entry.DataBlk == in_msg.DataBlk); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty; } } @@ -773,17 +800,18 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT } else { L1IcacheMemory.deallocate(address); } + unset_cache_entry(); } action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") { - if (L1DcacheMemory.isTagPresent(address) == false) { - L1DcacheMemory.allocate(address, new Entry); + if ((is_invalid(cache_entry))) { + set_cache_entry(L1DcacheMemory.allocate(address, new Entry)); } } action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") { - if (L1IcacheMemory.isTagPresent(address) == false) { - L1IcacheMemory.allocate(address, new Entry); + if ((is_invalid(cache_entry))) { + set_cache_entry(L1IcacheMemory.allocate(address, new Entry)); } } @@ -1173,4 +1201,3 @@ if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestT l_popForwardQueue; } } - diff --git a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm index 7c6021bae..a638b171f 100644 --- a/src/mem/protocol/MOESI_CMP_directory-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_directory-L2cache.sm @@ -218,40 +218,30 @@ machine(L2Cache, "Token protocol") } - TBETable L2_TBEs, template_hack="<L2Cache_TBE>"; + TBETable TBEs, template_hack="<L2Cache_TBE>"; PerfectCacheMemory localDirectory, template_hack="<L2Cache_DirEntry>"; + void set_cache_entry(AbstractCacheEntry b); + void unset_cache_entry(); + void set_tbe(TBE b); + void unset_tbe(); - Entry getL2CacheEntry(Address addr), return_by_ref="yes" { - if (L2cacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L2cacheMemory[addr]); - } else { - return static_cast(Entry, L2cacheMemory[addr]); - } - } - - void changePermission(Address addr, AccessPermission permission) { - if (L2cacheMemory.isTagPresent(addr)) { - return L2cacheMemory.changePermission(addr, permission); - } - } - - bool isCacheTagPresent(Address addr) { - return (L2cacheMemory.isTagPresent(addr) ); + Entry getCacheEntry(Address address), return_by_pointer="yes" { + return static_cast(Entry, "pointer", L2cacheMemory[address]); } bool isDirTagPresent(Address addr) { return (localDirectory.isTagPresent(addr) ); } - bool isOnlySharer(Address addr, MachineID shar_id) { - if (isCacheTagPresent(addr)) { + bool isOnlySharer(Entry cache_entry, Address addr, MachineID shar_id) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - if (getL2CacheEntry(addr).Sharers.count() > 1) { + if (cache_entry.Sharers.count() > 1) { return false; } - else if (getL2CacheEntry(addr).Sharers.count() == 1) { - if (getL2CacheEntry(addr).Sharers.isElement(shar_id)) { + else if (cache_entry.Sharers.count() == 1) { + if (cache_entry.Sharers.isElement(shar_id)) { return true; } else { @@ -285,27 +275,29 @@ machine(L2Cache, "Token protocol") } } - void copyCacheStateToDir(Address addr) { + void copyCacheStateToDir(Entry cache_entry, Address addr) { assert(localDirectory.isTagPresent(addr) == false); + assert(is_valid(cache_entry)); localDirectory.allocate(addr); - localDirectory[addr].DirState := getL2CacheEntry(addr).CacheState; - localDirectory[addr].Sharers := getL2CacheEntry(addr).Sharers; - localDirectory[addr].Owner := getL2CacheEntry(addr).Owner; - localDirectory[addr].OwnerValid := getL2CacheEntry(addr).OwnerValid; + localDirectory[addr].DirState := cache_entry.CacheState; + localDirectory[addr].Sharers := cache_entry.Sharers; + localDirectory[addr].Owner := cache_entry.Owner; + localDirectory[addr].OwnerValid := cache_entry.OwnerValid; } - void copyDirToCache(Address addr) { - getL2CacheEntry(addr).Sharers := localDirectory[addr].Sharers; - getL2CacheEntry(addr).Owner := localDirectory[addr].Owner; - getL2CacheEntry(addr).OwnerValid := localDirectory[addr].OwnerValid; + void copyDirToCache(Entry cache_entry, Address addr) { + assert(is_valid(cache_entry)); + cache_entry.Sharers := localDirectory[addr].Sharers; + cache_entry.Owner := localDirectory[addr].Owner; + cache_entry.OwnerValid := localDirectory[addr].OwnerValid; } - void recordLocalSharerInDir(Address addr, MachineID shar_id) { - if (isCacheTagPresent(addr)) { + void recordLocalSharerInDir(Entry cache_entry, Address addr, MachineID shar_id) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - getL2CacheEntry(addr).Sharers.add(shar_id); + cache_entry.Sharers.add(shar_id); } else { if (localDirectory.isTagPresent(addr) == false) { @@ -317,13 +309,13 @@ machine(L2Cache, "Token protocol") } } - void recordNewLocalExclusiveInDir(Address addr, MachineID exc_id) { + void recordNewLocalExclusiveInDir(Entry cache_entry, Address addr, MachineID exc_id) { - if (isCacheTagPresent(addr)) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - getL2CacheEntry(addr).Sharers.clear(); - getL2CacheEntry(addr).OwnerValid := true; - getL2CacheEntry(addr).Owner := exc_id; + cache_entry.Sharers.clear(); + cache_entry.OwnerValid := true; + cache_entry.Owner := exc_id; } else { if (localDirectory.isTagPresent(addr) == false) { @@ -335,12 +327,11 @@ machine(L2Cache, "Token protocol") } } - - void removeAllLocalSharersFromDir(Address addr) { - if (isCacheTagPresent(addr)) { + void removeAllLocalSharersFromDir(Entry cache_entry, Address addr) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - getL2CacheEntry(addr).Sharers.clear(); - getL2CacheEntry(addr).OwnerValid := false; + cache_entry.Sharers.clear(); + cache_entry.OwnerValid := false; } else { localDirectory[addr].Sharers.clear(); @@ -348,88 +339,84 @@ machine(L2Cache, "Token protocol") } } - void removeSharerFromDir(Address addr, MachineID sender) { - if (isCacheTagPresent(addr)) { + void removeSharerFromDir(Entry cache_entry, Address addr, MachineID sender) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - getL2CacheEntry(addr).Sharers.remove(sender); + cache_entry.Sharers.remove(sender); } else { localDirectory[addr].Sharers.remove(sender); } } - void removeOwnerFromDir(Address addr, MachineID sender) { - if (isCacheTagPresent(addr)) { + void removeOwnerFromDir(Entry cache_entry, Address addr, MachineID sender) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - getL2CacheEntry(addr).OwnerValid := false; + cache_entry.OwnerValid := false; } else { localDirectory[addr].OwnerValid := false; } } - bool isLocalSharer(Address addr, MachineID shar_id) { - if (isCacheTagPresent(addr)) { + bool isLocalSharer(Entry cache_entry, Address addr, MachineID shar_id) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - return getL2CacheEntry(addr).Sharers.isElement(shar_id); + return cache_entry.Sharers.isElement(shar_id); } else { return localDirectory[addr].Sharers.isElement(shar_id); } - } - NetDest getLocalSharers(Address addr) { - if (isCacheTagPresent(addr)) { + NetDest getLocalSharers(Entry cache_entry, Address addr) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - return getL2CacheEntry(addr).Sharers; + return cache_entry.Sharers; } else { return localDirectory[addr].Sharers; } - } - MachineID getLocalOwner(Address addr) { - if (isCacheTagPresent(addr)) { + MachineID getLocalOwner(Entry cache_entry, Address addr) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - return getL2CacheEntry(addr).Owner; + return cache_entry.Owner; } else { return localDirectory[addr].Owner; } - } - - int countLocalSharers(Address addr) { - if (isCacheTagPresent(addr)) { + int countLocalSharers(Entry cache_entry, Address addr) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - return getL2CacheEntry(addr).Sharers.count(); + return cache_entry.Sharers.count(); } else { return localDirectory[addr].Sharers.count(); } } - bool isLocalOwnerValid(Address addr) { - if (isCacheTagPresent(addr)) { + bool isLocalOwnerValid(Entry cache_entry, Address addr) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - return getL2CacheEntry(addr).OwnerValid; + return cache_entry.OwnerValid; } else { return localDirectory[addr].OwnerValid; } } - int countLocalSharersExceptRequestor(Address addr, MachineID requestor) { - if (isCacheTagPresent(addr)) { + int countLocalSharersExceptRequestor(Entry cache_entry, Address addr, MachineID requestor) { + if (is_valid(cache_entry)) { assert (localDirectory.isTagPresent(addr) == false); - if (getL2CacheEntry(addr).Sharers.isElement(requestor)) { - return ( getL2CacheEntry(addr).Sharers.count() - 1 ); + if (cache_entry.Sharers.isElement(requestor)) { + return ( cache_entry.Sharers.count() - 1 ); } else { - return getL2CacheEntry(addr).Sharers.count(); + return cache_entry.Sharers.count(); } } else { @@ -442,14 +429,12 @@ machine(L2Cache, "Token protocol") } } + State getState(TBE tbe, Entry cache_entry, Address addr) { - - State getState(Address addr) { - - if (L2_TBEs.isPresent(addr)) { - return L2_TBEs[addr].TBEState; - } else if (isCacheTagPresent(addr)) { - return getL2CacheEntry(addr).CacheState; + if (is_valid(tbe)) { + return tbe.TBEState; + } else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } else if (isDirTagPresent(addr)) { return localDirectory[addr].DirState; } else { @@ -457,20 +442,15 @@ machine(L2Cache, "Token protocol") } } - std::string getStateStr(Address addr) { - return L2Cache_State_to_string(getState(addr)); - } - std::string getCoherenceRequestTypeStr(CoherenceRequestType type) { return CoherenceRequestType_to_string(type); } - - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { assert((localDirectory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false); - if (L2_TBEs.isPresent(addr)) { - L2_TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } if ( @@ -482,7 +462,7 @@ machine(L2Cache, "Token protocol") (state == State:OLSX) || (state == State:SLS) ) { - assert(isCacheTagPresent(addr)); + assert(is_valid(cache_entry)); } else if ( (state == State:ILS) || @@ -495,53 +475,24 @@ machine(L2Cache, "Token protocol") // assert(isCacheTagPresent(addr) == false); } - - - if (isCacheTagPresent(addr)) { - if ( ((getL2CacheEntry(addr).CacheState != State:M) && (state == State:M)) || - ((getL2CacheEntry(addr).CacheState != State:S) && (state == State:S)) || - ((getL2CacheEntry(addr).CacheState != State:O) && (state == State:O)) ) { - getL2CacheEntry(addr).CacheState := state; + if (is_valid(cache_entry)) { + if ( ((cache_entry.CacheState != State:M) && (state == State:M)) || + ((cache_entry.CacheState != State:S) && (state == State:S)) || + ((cache_entry.CacheState != State:O) && (state == State:O)) ) { + cache_entry.CacheState := state; // disable Coherence Checker for now // sequencer.checkCoherence(addr); } else { - getL2CacheEntry(addr).CacheState := state; + cache_entry.CacheState := state; } // Set permission - changePermission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else if (localDirectory.isTagPresent(addr)) { localDirectory[addr].DirState := state; } - - } - - - bool isBlockExclusive(Address addr) { - if (isCacheTagPresent(addr)) { - // the list of exclusive states below is likely incomplete - if ( (getL2CacheEntry(addr).CacheState == State:M) || - (getL2CacheEntry(addr).CacheState == State:MI) ) { - return true; - } - } - - return false; - } - - bool isBlockShared(Address addr) { - if (isCacheTagPresent(addr)) { - // the list of shared states below is likely incomplete - if ( (getL2CacheEntry(addr).CacheState == State:S) || - (getL2CacheEntry(addr).CacheState == State:O) || - (getL2CacheEntry(addr).CacheState == State:OI) || - (getL2CacheEntry(addr).CacheState == State:OXW) ) { - return true; - } - } - return false; } MessageBuffer triggerQueue, ordered="true"; @@ -553,7 +504,6 @@ machine(L2Cache, "Token protocol") out_port(triggerQueue_out, TriggerMsg, triggerQueue); - // ** IN_PORTS ** // Trigger Queue @@ -561,7 +511,8 @@ machine(L2Cache, "Token protocol") if (triggerQueue_in.isReady()) { peek(triggerQueue_in, TriggerMsg) { if (in_msg.Type == TriggerType:ALL_ACKS) { - trigger(Event:All_Acks, in_msg.Address); + trigger(Event:All_Acks, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { error("Unexpected message"); } @@ -576,20 +527,27 @@ machine(L2Cache, "Token protocol") peek(requestNetwork_in, RequestMsg) { if (in_msg.Type == CoherenceRequestType:GETX || in_msg.Type == CoherenceRequestType:DMA_WRITE) { if (in_msg.Requestor == machineID) { - trigger(Event:Own_GETX, in_msg.Address); + trigger(Event:Own_GETX, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { - trigger(Event:Fwd_GETX, in_msg.Address); + trigger(Event:Fwd_GETX, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } } else if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:Fwd_GETS, in_msg.Address); + trigger(Event:Fwd_GETS, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if(in_msg.Type == CoherenceRequestType:DMA_READ) { - trigger(Event:Fwd_DMA, in_msg.Address); + trigger(Event:Fwd_DMA, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:INV) { - trigger(Event:Inv, in_msg.Address); + trigger(Event:Inv, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:WB_ACK) { - trigger(Event:Writeback_Ack, in_msg.Address); + trigger(Event:Writeback_Ack, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:WB_NACK) { - trigger(Event:Writeback_Nack, in_msg.Address); + trigger(Event:Writeback_Nack, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { error("Unexpected message"); } @@ -602,19 +560,26 @@ machine(L2Cache, "Token protocol") peek(L1requestNetwork_in, RequestMsg) { assert(in_msg.Destination.isElement(machineID)); if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:L1_GETX, in_msg.Address); + trigger(Event:L1_GETX, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:L1_GETS, in_msg.Address); + trigger(Event:L1_GETS, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:PUTO) { - trigger(Event:L1_PUTO, in_msg.Address); + trigger(Event:L1_PUTO, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:PUTX) { - trigger(Event:L1_PUTX, in_msg.Address); + trigger(Event:L1_PUTX, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:PUTS) { - if (isOnlySharer(in_msg.Address, in_msg.Requestor)) { - trigger(Event:L1_PUTS_only, in_msg.Address); + Entry cache_entry := getCacheEntry(in_msg.Address); + if (isOnlySharer(cache_entry, in_msg.Address, in_msg.Requestor)) { + trigger(Event:L1_PUTS_only, in_msg.Address, + cache_entry, TBEs[in_msg.Address]); } else { - trigger(Event:L1_PUTS, in_msg.Address); + trigger(Event:L1_PUTS, in_msg.Address, + cache_entry, TBEs[in_msg.Address]); } } else { error("Unexpected message"); @@ -631,34 +596,48 @@ machine(L2Cache, "Token protocol") assert(in_msg.Destination.isElement(machineID)); if (in_msg.Type == CoherenceResponseType:ACK) { if (in_msg.SenderMachine == MachineType:L2Cache) { - trigger(Event:ExtAck, in_msg.Address); + trigger(Event:ExtAck, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else { - trigger(Event:IntAck, in_msg.Address); + trigger(Event:IntAck, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } } else if (in_msg.Type == CoherenceResponseType:DATA) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Data_Exclusive, in_msg.Address); + trigger(Event:Data_Exclusive, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) { - trigger(Event:Unblock, in_msg.Address); + trigger(Event:Unblock, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) { - trigger(Event:Exclusive_Unblock, in_msg.Address); + trigger(Event:Exclusive_Unblock, in_msg.Address, + getCacheEntry(in_msg.Address), TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) { - if (L2cacheMemory.isTagPresent(in_msg.Address) == false && + Entry cache_entry := getCacheEntry(in_msg.Address); + if (is_invalid(cache_entry) && L2cacheMemory.cacheAvail(in_msg.Address) == false) { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address)); + trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address), + getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address)), + TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]); } else { - trigger(Event:L1_WBDIRTYDATA, in_msg.Address); + trigger(Event:L1_WBDIRTYDATA, in_msg.Address, + cache_entry, TBEs[in_msg.Address]); } } else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN_DATA) { - if (L2cacheMemory.isTagPresent(in_msg.Address) == false && + Entry cache_entry := getCacheEntry(in_msg.Address); + if (is_invalid(cache_entry) && L2cacheMemory.cacheAvail(in_msg.Address) == false) { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address)); + trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address), + getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address)), + TBEs[L2cacheMemory.cacheProbe(in_msg.Address)]); } else { - trigger(Event:L1_WBCLEANDATA, in_msg.Address); + trigger(Event:L1_WBCLEANDATA, in_msg.Address, + cache_entry, TBEs[in_msg.Address]); } } else { error("Unexpected message"); @@ -731,134 +710,144 @@ machine(L2Cache, "Token protocol") } action(c_sendDataFromTBEToL1GETS, "c", desc="Send data from TBE to L1 requestors in TBE") { + assert(is_valid(tbe)); enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; - out_msg.Destination.addNetDest(L2_TBEs[address].L1_GetS_IDs); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - // out_msg.Dirty := L2_TBEs[address].Dirty; + out_msg.Destination.addNetDest(tbe.L1_GetS_IDs); + out_msg.DataBlk := tbe.DataBlk; + // out_msg.Dirty := tbe.Dirty; // shared data should be clean out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:Response_Data; } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, L2_TBEs[address].DataBlk); + address, tbe.DataBlk); } action(c_sendDataFromTBEToL1GETX, "\c", desc="Send data from TBE to L1 requestors in TBE") { + assert(is_valid(tbe)); enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; - out_msg.Destination.add(L2_TBEs[address].L1_GetX_ID); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - out_msg.Dirty := L2_TBEs[address].Dirty; - out_msg.Acks := L2_TBEs[address].Local_GETX_IntAcks; + out_msg.Destination.add(tbe.L1_GetX_ID); + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; + out_msg.Acks := tbe.Local_GETX_IntAcks; out_msg.MessageSize := MessageSizeType:Response_Data; } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, L2_TBEs[address].DataBlk); + address, tbe.DataBlk); } action(c_sendExclusiveDataFromTBEToL1GETS, "\cc", desc="Send data from TBE to L1 requestors in TBE") { + assert(is_valid(tbe)); enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; - out_msg.Destination.addNetDest(L2_TBEs[address].L1_GetS_IDs); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - out_msg.Dirty := L2_TBEs[address].Dirty; + out_msg.Destination.addNetDest(tbe.L1_GetS_IDs); + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } action(c_sendDataFromTBEToFwdGETX, "cc", desc="Send data from TBE to external GETX") { + assert(is_valid(tbe)); enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; - out_msg.Destination.add(L2_TBEs[address].Fwd_GetX_ID); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - out_msg.Dirty := L2_TBEs[address].Dirty; - out_msg.Acks := L2_TBEs[address].Fwd_GETX_ExtAcks; + out_msg.Destination.add(tbe.Fwd_GetX_ID); + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; + out_msg.Acks := tbe.Fwd_GETX_ExtAcks; out_msg.MessageSize := MessageSizeType:Response_Data; } } action(c_sendDataFromTBEToFwdGETS, "ccc", desc="Send data from TBE to external GETX") { + assert(is_valid(tbe)); enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; - out_msg.Destination.addNetDest(L2_TBEs[address].Fwd_GetS_IDs); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - // out_msg.Dirty := L2_TBEs[address].Dirty; + out_msg.Destination.addNetDest(tbe.Fwd_GetS_IDs); + out_msg.DataBlk := tbe.DataBlk; + // out_msg.Dirty := tbe.Dirty; // shared data should be clean out_msg.Dirty := false; - out_msg.Acks := L2_TBEs[address].Fwd_GETX_ExtAcks; + out_msg.Acks := tbe.Fwd_GETX_ExtAcks; out_msg.MessageSize := MessageSizeType:Response_Data; } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, L2_TBEs[address].DataBlk); + address, tbe.DataBlk); } action(c_sendExclusiveDataFromTBEToFwdGETS, "\ccc", desc="Send data from TBE to external GETX") { + assert(is_valid(tbe)); enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; - out_msg.Destination.addNetDest(L2_TBEs[address].Fwd_GetS_IDs); - out_msg.DataBlk := L2_TBEs[address].DataBlk; - out_msg.Dirty := L2_TBEs[address].Dirty; - out_msg.Acks := L2_TBEs[address].Fwd_GETX_ExtAcks; + out_msg.Destination.addNetDest(tbe.Fwd_GetS_IDs); + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; + out_msg.Acks := tbe.Fwd_GETX_ExtAcks; out_msg.MessageSize := MessageSizeType:Response_Data; } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, L2_TBEs[address].DataBlk); + address, tbe.DataBlk); } action(d_sendDataToL1GETS, "d", desc="Send data directly to L1 requestor") { + assert(is_valid(cache_entry)); peek(L1requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - // out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; // shared data should be clean out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data; } } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getL2CacheEntry(address).DataBlk); + address, cache_entry.DataBlk); } action(d_sendDataToL1GETX, "\d", desc="Send data and a token from TBE to L1 requestor") { + assert(is_valid(cache_entry)); peek(L1requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data; - out_msg.Acks := L2_TBEs[address].Local_GETX_IntAcks; + out_msg.Acks := tbe.Local_GETX_IntAcks; } } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getL2CacheEntry(address).DataBlk); + address, cache_entry.DataBlk); } action(dd_sendDataToFwdGETX, "dd", desc="send data") { + assert(is_valid(cache_entry)); peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; @@ -866,44 +855,46 @@ machine(L2Cache, "Token protocol") out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.Acks := in_msg.Acks; } } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getL2CacheEntry(address).DataBlk); + address, cache_entry.DataBlk); } action(dd_sendDataToFwdGETS, "\dd", desc="send data") { + assert(is_valid(cache_entry)); peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - // out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; // shared data should be clean out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:Response_Data; } } DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getL2CacheEntry(address).DataBlk); + address, cache_entry.DataBlk); } action(dd_sendExclusiveDataToFwdGETS, "\d\d", desc="send data") { + assert(is_valid(cache_entry)); peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -911,12 +902,13 @@ machine(L2Cache, "Token protocol") action(e_sendAck, "e", desc="Send ack with the tokens we've collected thus far.") { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; - out_msg.Destination.add( L2_TBEs[address].Fwd_GetX_ID); + out_msg.Destination.add( tbe.Fwd_GetX_ID); out_msg.Acks := 0 - 1; out_msg.MessageSize := MessageSizeType:Response_Control; } @@ -938,24 +930,26 @@ machine(L2Cache, "Token protocol") action(e_sendAckToL1RequestorFromTBE, "eee", desc="Send ack with the tokens we've collected thus far.") { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; - out_msg.Destination.add(L2_TBEs[address].L1_GetX_ID); + out_msg.Destination.add(tbe.L1_GetX_ID); out_msg.Acks := 0 - 1; out_msg.MessageSize := MessageSizeType:Response_Control; } } action(ee_sendLocalInv, "\ee", desc="Send local invalidates") { - L2_TBEs[address].NumIntPendingAcks := countLocalSharers(address); + assert(is_valid(tbe)); + tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address); DPRINTF(RubySlicc, "Address: %s, Local Sharers: %s, Pending Acks: %d\n", - address, getLocalSharers(address), - L2_TBEs[address].NumIntPendingAcks); - if (isLocalOwnerValid(address)) { - L2_TBEs[address].NumIntPendingAcks := L2_TBEs[address].NumIntPendingAcks + 1; - DPRINTF(RubySlicc, "%s\n", getLocalOwner(address)); + address, getLocalSharers(cache_entry, address), + tbe.NumIntPendingAcks); + if (isLocalOwnerValid(cache_entry, address)) { + tbe.NumIntPendingAcks := tbe.NumIntPendingAcks + 1; + DPRINTF(RubySlicc, "%s\n", getLocalOwner(cache_entry, address)); } enqueue( localRequestNetwork_out, RequestMsg, latency=response_latency ) { @@ -963,10 +957,10 @@ machine(L2Cache, "Token protocol") out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := machineID; out_msg.RequestorMachine := MachineType:L2Cache; - out_msg.Destination.addNetDest(getLocalSharers(address)); - if (isLocalOwnerValid(address)) + out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address)); + if (isLocalOwnerValid(cache_entry, address)) { - out_msg.Destination.add(getLocalOwner(address)); + out_msg.Destination.add(getLocalOwner(cache_entry, address)); } out_msg.MessageSize := MessageSizeType:Invalidate_Control; } @@ -975,38 +969,40 @@ machine(L2Cache, "Token protocol") action(ee_sendLocalInvSharersOnly, "\eee", desc="Send local invalidates to sharers if they exist") { // assert(countLocalSharers(address) > 0); - L2_TBEs[address].NumIntPendingAcks := countLocalSharers(address); + assert(is_valid(tbe)); + tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address); - if (countLocalSharers(address) > 0) { + if (countLocalSharers(cache_entry, address) > 0) { enqueue( localRequestNetwork_out, RequestMsg, latency=response_latency ) { out_msg.Address := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := machineID; out_msg.RequestorMachine := MachineType:L2Cache; - out_msg.Destination.addNetDest(getLocalSharers(address)); + out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address)); out_msg.MessageSize := MessageSizeType:Invalidate_Control; } } } action(ee_addLocalIntAck, "e\ee", desc="add a local ack to wait for") { - L2_TBEs[address].NumIntPendingAcks := L2_TBEs[address].NumIntPendingAcks + 1; + assert(is_valid(tbe)); + tbe.NumIntPendingAcks := tbe.NumIntPendingAcks + 1; } action(ee_issueLocalInvExceptL1Requestor, "\eeee", desc="Send local invalidates to sharers if they exist") { peek(L1requestNetwork_in, RequestMsg) { // assert(countLocalSharers(address) > 0); - if (countLocalSharers(address) == 0) { - L2_TBEs[address].NumIntPendingAcks := 0; + if (countLocalSharers(cache_entry, address) == 0) { + tbe.NumIntPendingAcks := 0; } else { - if (isLocalSharer(address, in_msg.Requestor)) { - L2_TBEs[address].NumIntPendingAcks := countLocalSharers(address) - 1; + if (isLocalSharer(cache_entry, address, in_msg.Requestor)) { + tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address) - 1; } else { - L2_TBEs[address].NumIntPendingAcks := countLocalSharers(address); + tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address); } enqueue( localRequestNetwork_out, RequestMsg, latency=response_latency ) { @@ -1014,7 +1010,7 @@ machine(L2Cache, "Token protocol") out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := in_msg.Requestor; out_msg.RequestorMachine := MachineType:L1Cache; - out_msg.Destination.addNetDest(getLocalSharers(address)); + out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address)); out_msg.Destination.remove(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Invalidate_Control; } @@ -1023,24 +1019,25 @@ machine(L2Cache, "Token protocol") } action(ee_issueLocalInvExceptL1RequestorInTBE, "\eeeeee", desc="Send local invalidates to sharers if they exist") { - if (countLocalSharers(address) == 0) { - L2_TBEs[address].NumIntPendingAcks := 0; + assert(is_valid(tbe)); + if (countLocalSharers(cache_entry, address) == 0) { + tbe.NumIntPendingAcks := 0; } else { - if (isLocalSharer(address, L2_TBEs[address].L1_GetX_ID)) { - L2_TBEs[address].NumIntPendingAcks := countLocalSharers(address) - 1; + if (isLocalSharer(cache_entry, address, tbe.L1_GetX_ID)) { + tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address) - 1; } else { - L2_TBEs[address].NumIntPendingAcks := countLocalSharers(address); + tbe.NumIntPendingAcks := countLocalSharers(cache_entry, address); } } enqueue( localRequestNetwork_out, RequestMsg, latency=response_latency ) { out_msg.Address := address; out_msg.Type := CoherenceRequestType:INV; - out_msg.Requestor := L2_TBEs[address].L1_GetX_ID; + out_msg.Requestor := tbe.L1_GetX_ID; out_msg.RequestorMachine := MachineType:L1Cache; - out_msg.Destination.addNetDest(getLocalSharers(address)); - out_msg.Destination.remove(L2_TBEs[address].L1_GetX_ID); + out_msg.Destination.addNetDest(getLocalSharers(cache_entry, address)); + out_msg.Destination.remove(tbe.L1_GetX_ID); out_msg.MessageSize := MessageSizeType:Invalidate_Control; } } @@ -1072,64 +1069,69 @@ machine(L2Cache, "Token protocol") action(g_recordLocalSharer, "g", desc="Record new local sharer from unblock message") { peek(responseNetwork_in, ResponseMsg) { - recordLocalSharerInDir(in_msg.Address, in_msg.Sender); + recordLocalSharerInDir(cache_entry, in_msg.Address, in_msg.Sender); } } action(g_recordLocalExclusive, "\g", desc="Record new local exclusive sharer from unblock message") { peek(responseNetwork_in, ResponseMsg) { - recordNewLocalExclusiveInDir(address, in_msg.Sender); + recordNewLocalExclusiveInDir(cache_entry, address, in_msg.Sender); } } action(gg_clearLocalSharers, "gg", desc="Clear local sharers") { - removeAllLocalSharersFromDir(address); + removeAllLocalSharersFromDir(cache_entry, address); } action(gg_clearSharerFromL1Response, "\gg", desc="Clear sharer from L1 response queue") { peek(responseNetwork_in, ResponseMsg) { - removeSharerFromDir(in_msg.Address, in_msg.Sender); + removeSharerFromDir(cache_entry, in_msg.Address, in_msg.Sender); } } action(gg_clearOwnerFromL1Response, "g\g", desc="Clear sharer from L1 response queue") { peek(responseNetwork_in, ResponseMsg) { - removeOwnerFromDir(in_msg.Address, in_msg.Sender); + removeOwnerFromDir(cache_entry, in_msg.Address, in_msg.Sender); } } action(h_countLocalSharersExceptRequestor, "h", desc="counts number of acks needed for L1 GETX") { peek(L1requestNetwork_in, RequestMsg) { - L2_TBEs[address].Local_GETX_IntAcks := countLocalSharersExceptRequestor(address, in_msg.Requestor); + assert(is_valid(tbe)); + tbe.Local_GETX_IntAcks := countLocalSharersExceptRequestor(cache_entry, address, in_msg.Requestor); } } action(h_clearIntAcks, "\h", desc="clear IntAcks") { - L2_TBEs[address].Local_GETX_IntAcks := 0; + assert(is_valid(tbe)); + tbe.Local_GETX_IntAcks := 0; } action(hh_countLocalSharersExceptL1GETXRequestorInTBE, "hh", desc="counts number of acks needed for L1 GETX") { - L2_TBEs[address].Local_GETX_IntAcks := countLocalSharersExceptRequestor(address, L2_TBEs[address].L1_GetX_ID); + assert(is_valid(tbe)); + tbe.Local_GETX_IntAcks := countLocalSharersExceptRequestor(cache_entry, address, tbe.L1_GetX_ID); } action(i_copyDataToTBE, "\i", desc="Copy data from response queue to TBE") { peek(responseNetwork_in, ResponseMsg) { - L2_TBEs[address].DataBlk := in_msg.DataBlk; - L2_TBEs[address].Dirty := in_msg.Dirty; + assert(is_valid(tbe)); + tbe.DataBlk := in_msg.DataBlk; + tbe.Dirty := in_msg.Dirty; } } action(i_allocateTBE, "i", desc="Allocate TBE for internal/external request(isPrefetch=0, number of invalidates=0)") { - check_allocate(L2_TBEs); - L2_TBEs.allocate(address); - if(isCacheTagPresent(address)) { - L2_TBEs[address].DataBlk := getL2CacheEntry(address).DataBlk; - L2_TBEs[address].Dirty := getL2CacheEntry(address).Dirty; + check_allocate(TBEs); + TBEs.allocate(address); + set_tbe(TBEs[address]); + if(is_valid(cache_entry)) { + tbe.DataBlk := cache_entry.DataBlk; + tbe.Dirty := cache_entry.Dirty; } - L2_TBEs[address].NumIntPendingAcks := 0; // default value - L2_TBEs[address].NumExtPendingAcks := 0; // default value - L2_TBEs[address].Fwd_GetS_IDs.clear(); - L2_TBEs[address].L1_GetS_IDs.clear(); + tbe.NumIntPendingAcks := 0; // default value + tbe.NumExtPendingAcks := 0; // default value + tbe.Fwd_GetS_IDs.clear(); + tbe.L1_GetS_IDs.clear(); } @@ -1141,7 +1143,7 @@ machine(L2Cache, "Token protocol") out_msg.Type := in_msg.Type; out_msg.Requestor := machineID; out_msg.RequestorMachine := MachineType:L2Cache; - out_msg.Destination.add(getLocalOwner(in_msg.Address)); + out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.Address)); out_msg.Type := in_msg.Type; out_msg.MessageSize := MessageSizeType:Forwarded_Control; out_msg.Acks := 0 - 1; @@ -1166,13 +1168,14 @@ machine(L2Cache, "Token protocol") action(k_forwardLocalGETXToLocalOwner, "\k", desc="Forward local request to local owner") { enqueue( localRequestNetwork_out, RequestMsg, latency=response_latency ) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:GETX; - out_msg.Requestor := L2_TBEs[address].L1_GetX_ID; + out_msg.Requestor := tbe.L1_GetX_ID; out_msg.RequestorMachine := MachineType:L1Cache; out_msg.Destination.add(localDirectory[address].Owner); out_msg.MessageSize := MessageSizeType:Forwarded_Control; - out_msg.Acks := 1 + L2_TBEs[address].Local_GETX_IntAcks; + out_msg.Acks := 1 + tbe.Local_GETX_IntAcks; } } @@ -1184,7 +1187,7 @@ machine(L2Cache, "Token protocol") out_msg.Type := CoherenceRequestType:GETX; out_msg.Requestor := in_msg.Requestor; out_msg.RequestorMachine := MachineType:L1Cache; - out_msg.Destination.add(getLocalOwner(in_msg.Address)); + out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.Address)); out_msg.MessageSize := MessageSizeType:Forwarded_Control; out_msg.Acks := 1; } @@ -1198,7 +1201,7 @@ machine(L2Cache, "Token protocol") out_msg.Type := CoherenceRequestType:GETS; out_msg.Requestor := in_msg.Requestor; out_msg.RequestorMachine := MachineType:L1Cache; - out_msg.Destination.add(getLocalOwner(in_msg.Address)); + out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.Address)); out_msg.MessageSize := MessageSizeType:Forwarded_Control; } } @@ -1252,19 +1255,22 @@ machine(L2Cache, "Token protocol") action(m_decrementNumberOfMessagesInt, "\m", desc="Decrement the number of messages for which we're waiting") { peek(responseNetwork_in, ResponseMsg) { - L2_TBEs[address].NumIntPendingAcks := L2_TBEs[address].NumIntPendingAcks + in_msg.Acks; + assert(is_valid(tbe)); + tbe.NumIntPendingAcks := tbe.NumIntPendingAcks + in_msg.Acks; } } action(m_decrementNumberOfMessagesExt, "\mmm", desc="Decrement the number of messages for which we're waiting") { peek(responseNetwork_in, ResponseMsg) { - L2_TBEs[address].NumExtPendingAcks := L2_TBEs[address].NumExtPendingAcks - in_msg.Acks; + assert(is_valid(tbe)); + tbe.NumExtPendingAcks := tbe.NumExtPendingAcks - in_msg.Acks; } } action(mm_decrementNumberOfMessagesExt, "\mm", desc="Decrement the number of messages for which we're waiting") { peek(requestNetwork_in, RequestMsg) { - L2_TBEs[address].NumExtPendingAcks := L2_TBEs[address].NumExtPendingAcks - in_msg.Acks; + assert(is_valid(tbe)); + tbe.NumExtPendingAcks := tbe.NumExtPendingAcks - in_msg.Acks; } } @@ -1282,7 +1288,8 @@ machine(L2Cache, "Token protocol") action(o_checkForIntCompletion, "\o", desc="Check if we have received all the messages required for completion") { - if (L2_TBEs[address].NumIntPendingAcks == 0) { + assert(is_valid(tbe)); + if (tbe.NumIntPendingAcks == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; out_msg.Type := TriggerType:ALL_ACKS; @@ -1291,7 +1298,8 @@ machine(L2Cache, "Token protocol") } action(o_checkForExtCompletion, "\oo", desc="Check if we have received all the messages required for completion") { - if (L2_TBEs[address].NumExtPendingAcks == 0) { + assert(is_valid(tbe)); + if (tbe.NumExtPendingAcks == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; out_msg.Type := TriggerType:ALL_ACKS; @@ -1302,83 +1310,92 @@ machine(L2Cache, "Token protocol") action( qq_sendDataFromTBEToMemory, "qq", desc="Send data from TBE to directory") { enqueue(responseNetwork_out, ResponseMsg, latency=response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:L2Cache; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.Dirty := L2_TBEs[address].Dirty; - if (L2_TBEs[address].Dirty) { + out_msg.Dirty := tbe.Dirty; + if (tbe.Dirty) { out_msg.Type := CoherenceResponseType:WRITEBACK_DIRTY_DATA; - out_msg.DataBlk := L2_TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Data; } else { out_msg.Type := CoherenceResponseType:WRITEBACK_CLEAN_ACK; // NOTE: in a real system this would not send data. We send // data here only so we can check it at the memory - out_msg.DataBlk := L2_TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Control; } } } action( r_setMRU, "\rrr", desc="manually set the MRU bit for cache line" ) { - if(isCacheTagPresent(address)) { + if(is_valid(cache_entry)) { L2cacheMemory.setMRU(address); } } action( s_recordGetXL1ID, "ss", desc="record local GETX requestor") { peek(L1requestNetwork_in, RequestMsg) { - L2_TBEs[address].L1_GetX_ID := in_msg.Requestor; + assert(is_valid(tbe)); + tbe.L1_GetX_ID := in_msg.Requestor; } } action(s_deallocateTBE, "s", desc="Deallocate external TBE") { - L2_TBEs.deallocate(address); + TBEs.deallocate(address); + unset_tbe(); } action( s_recordGetSL1ID, "\ss", desc="record local GETS requestor") { peek(L1requestNetwork_in, RequestMsg) { - L2_TBEs[address].L1_GetS_IDs.add(in_msg.Requestor); + assert(is_valid(tbe)); + tbe.L1_GetS_IDs.add(in_msg.Requestor); } } action(t_recordFwdXID, "t", desc="record global GETX requestor") { peek(requestNetwork_in, RequestMsg) { - L2_TBEs[address].Fwd_GetX_ID := in_msg.Requestor; - L2_TBEs[address].Fwd_GETX_ExtAcks := in_msg.Acks; + assert(is_valid(tbe)); + tbe.Fwd_GetX_ID := in_msg.Requestor; + tbe.Fwd_GETX_ExtAcks := in_msg.Acks; } } action(t_recordFwdSID, "\t", desc="record global GETS requestor") { peek(requestNetwork_in, RequestMsg) { - L2_TBEs[address].Fwd_GetS_IDs.clear(); - L2_TBEs[address].Fwd_GetS_IDs.add(in_msg.Requestor); + assert(is_valid(tbe)); + tbe.Fwd_GetS_IDs.clear(); + tbe.Fwd_GetS_IDs.add(in_msg.Requestor); } } action(u_writeDataToCache, "u", desc="Write data to cache") { peek(responseNetwork_in, ResponseMsg) { - getL2CacheEntry(address).DataBlk := in_msg.DataBlk; - if ((getL2CacheEntry(address).Dirty == false) && in_msg.Dirty) { - getL2CacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + if ((cache_entry.Dirty == false) && in_msg.Dirty) { + cache_entry.Dirty := in_msg.Dirty; } } } action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") { - L2cacheMemory.allocate(address, new Entry); + set_cache_entry(L2cacheMemory.allocate(address, new Entry)); } action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") { L2cacheMemory.deallocate(address); + unset_cache_entry(); } action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") { peek(responseNetwork_in, ResponseMsg) { - assert(getL2CacheEntry(address).DataBlk == in_msg.DataBlk); + assert(is_valid(cache_entry)); + assert(cache_entry.DataBlk == in_msg.DataBlk); } } @@ -1389,25 +1406,18 @@ machine(L2Cache, "Token protocol") } } - - action(y_copyCacheStateToDir, "y", desc="Copy cache state to directory state") { - - assert(isCacheTagPresent(address)); - copyCacheStateToDir(address); - + copyCacheStateToDir(cache_entry, address); } action(y_copyDirToCacheAndRemove, "/y", desc="Copy dir state to cache and remove") { - copyDirToCache(address); + copyDirToCache(cache_entry, address); localDirectory.deallocate(address); } - action(z_stall, "z", desc="Stall") { } - action(zz_recycleL1RequestQueue, "zz", desc="Send the head of the mandatory queue to the back of the queue.") { peek(L1requestNetwork_in, RequestMsg) { APPEND_TRANSITION_COMMENT(in_msg.Requestor); @@ -1422,7 +1432,6 @@ machine(L2Cache, "Token protocol") requestNetwork_in.recycle(); } - action(zz_recycleResponseQueue, "\z\z", desc="Send the head of the mandatory queue to the back of the queue.") { peek(responseNetwork_in, ResponseMsg) { APPEND_TRANSITION_COMMENT(in_msg.Sender); @@ -2603,4 +2612,3 @@ machine(L2Cache, "Token protocol") m_popRequestQueue; } } - diff --git a/src/mem/protocol/MOESI_CMP_directory-dir.sm b/src/mem/protocol/MOESI_CMP_directory-dir.sm index 36e96cf41..19b69c64c 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dir.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dir.sm @@ -119,15 +119,18 @@ machine(Directory, "Directory protocol") // ** OBJECTS ** TBETable TBEs, template_hack="<Directory_TBE>"; + void set_tbe(TBE b); + void unset_tbe(); + Entry getDirectoryEntry(Address addr), return_by_ref="yes" { return static_cast(Entry, directory[addr]); } - State getState(Address addr) { + State getState(TBE tbe, Address addr) { return getDirectoryEntry(addr).DirectoryState; } - void setState(Address addr, State state) { + void setState(TBE tbe, Address addr, State state) { if (directory.isPresent(addr)) { if (state == State:I) { @@ -204,18 +207,24 @@ machine(Directory, "Directory protocol") peek(unblockNetwork_in, ResponseMsg) { if (in_msg.Type == CoherenceResponseType:UNBLOCK) { if (getDirectoryEntry(in_msg.Address).WaitingUnblocks == 1) { - trigger(Event:Last_Unblock, in_msg.Address); + trigger(Event:Last_Unblock, in_msg.Address, + TBEs[in_msg.Address]); } else { - trigger(Event:Unblock, in_msg.Address); + trigger(Event:Unblock, in_msg.Address, + TBEs[in_msg.Address]); } } else if (in_msg.Type == CoherenceResponseType:UNBLOCK_EXCLUSIVE) { - trigger(Event:Exclusive_Unblock, in_msg.Address); + trigger(Event:Exclusive_Unblock, in_msg.Address, + TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:WRITEBACK_DIRTY_DATA) { - trigger(Event:Dirty_Writeback, in_msg.Address); + trigger(Event:Dirty_Writeback, in_msg.Address, + TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:WRITEBACK_CLEAN_ACK) { - trigger(Event:Clean_Writeback, in_msg.Address); + trigger(Event:Clean_Writeback, in_msg.Address, + TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, + TBEs[in_msg.Address]); } else { error("Invalid message"); } @@ -227,19 +236,21 @@ machine(Directory, "Directory protocol") if (requestQueue_in.isReady()) { peek(requestQueue_in, RequestMsg) { if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:GETS, in_msg.Address); + trigger(Event:GETS, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:GETX, in_msg.Address); + trigger(Event:GETX, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:PUTX) { - trigger(Event:PUTX, in_msg.Address); + trigger(Event:PUTX, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:PUTO) { - trigger(Event:PUTO, in_msg.Address); + trigger(Event:PUTO, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:PUTO_SHARERS) { - trigger(Event:PUTO_SHARERS, in_msg.Address); + trigger(Event:PUTO_SHARERS, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:DMA_READ) { - trigger(Event:DMA_READ, makeLineAddress(in_msg.Address)); + trigger(Event:DMA_READ, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else if (in_msg.Type == CoherenceRequestType:DMA_WRITE) { - trigger(Event:DMA_WRITE, makeLineAddress(in_msg.Address)); + trigger(Event:DMA_WRITE, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else { error("Invalid message"); } @@ -252,9 +263,9 @@ machine(Directory, "Directory protocol") if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { - trigger(Event:Memory_Data, in_msg.Address); + trigger(Event:Memory_Data, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { - trigger(Event:Memory_Ack, in_msg.Address); + trigger(Event:Memory_Ack, in_msg.Address, TBEs[in_msg.Address]); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Invalid message"); @@ -271,6 +282,7 @@ machine(Directory, "Directory protocol") out_msg.Address := address; out_msg.Type := CoherenceRequestType:WB_ACK; out_msg.Requestor := in_msg.Requestor; + out_msg.RequestorMachine := MachineType:Directory; out_msg.Destination.add(in_msg.Requestor); out_msg.MessageSize := MessageSizeType:Writeback_Control; } @@ -481,9 +493,9 @@ machine(Directory, "Directory protocol") out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; out_msg.Sender := machineID; - if (TBEs.isPresent(address)) { - out_msg.OriginalRequestorMachId := TBEs[address].Requestor; - } + if (is_valid(tbe)) { + out_msg.OriginalRequestorMachId := tbe.Requestor; + } out_msg.DataBlk := in_msg.DataBlk; out_msg.MessageSize := in_msg.MessageSize; //out_msg.Prefetch := false; @@ -543,8 +555,8 @@ machine(Directory, "Directory protocol") out_msg.Address := address; out_msg.Sender := machineID; out_msg.SenderMachine := MachineType:Directory; - if (TBEs.isPresent(address)) { - out_msg.Destination.add(TBEs[address].Requestor); + if (is_valid(tbe)) { + out_msg.Destination.add(tbe.Requestor); } out_msg.DataBlk := in_msg.DataBlk; out_msg.Acks := getDirectoryEntry(address).Sharers.count(); // for dma requests @@ -561,23 +573,25 @@ machine(Directory, "Directory protocol") } action(l_writeDMADataToMemoryFromTBE, "\ll", desc="Write data from a DMA_WRITE to memory") { - getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DataBlk, - addressOffset(TBEs[address].PhysicalAddress), - TBEs[address].Len); + assert(is_valid(tbe)); + getDirectoryEntry(address).DataBlk.copyPartial(tbe.DataBlk, + addressOffset(tbe.PhysicalAddress), tbe.Len); } action(v_allocateTBE, "v", desc="Allocate TBE entry") { peek (requestQueue_in, RequestMsg) { TBEs.allocate(address); - TBEs[address].PhysicalAddress := in_msg.Address; - TBEs[address].Len := in_msg.Len; - TBEs[address].DataBlk := in_msg.DataBlk; - TBEs[address].Requestor := in_msg.Requestor; + set_tbe(TBEs[address]); + tbe.PhysicalAddress := in_msg.Address; + tbe.Len := in_msg.Len; + tbe.DataBlk := in_msg.DataBlk; + tbe.Requestor := in_msg.Requestor; } } action(w_deallocateTBE, "w", desc="Deallocate TBE entry") { TBEs.deallocate(address); + unset_tbe(); } diff --git a/src/mem/protocol/MOESI_CMP_directory-dma.sm b/src/mem/protocol/MOESI_CMP_directory-dma.sm index 673e0c4cb..b129757b8 100644 --- a/src/mem/protocol/MOESI_CMP_directory-dma.sm +++ b/src/mem/protocol/MOESI_CMP_directory-dma.sm @@ -51,10 +51,13 @@ machine(DMA, "DMA Controller") TBETable TBEs, template_hack="<DMA_TBE>"; State cur_state; - State getState(Address addr) { + void set_tbe(TBE b); + void unset_tbe(); + + State getState(TBE tbe, Address addr) { return cur_state; } - void setState(Address addr, State state) { + void setState(TBE tbe, Address addr, State state) { cur_state := state; } @@ -83,9 +86,11 @@ machine(DMA, "DMA Controller") if (dmaRequestQueue_in.isReady()) { peek(dmaRequestQueue_in, SequencerMsg) { if (in_msg.Type == SequencerRequestType:LD ) { - trigger(Event:ReadRequest, in_msg.LineAddress); + trigger(Event:ReadRequest, in_msg.LineAddress, + TBEs[in_msg.LineAddress]); } else if (in_msg.Type == SequencerRequestType:ST) { - trigger(Event:WriteRequest, in_msg.LineAddress); + trigger(Event:WriteRequest, in_msg.LineAddress, + TBEs[in_msg.LineAddress]); } else { error("Invalid request type"); } @@ -97,12 +102,15 @@ machine(DMA, "DMA Controller") if (dmaResponseQueue_in.isReady()) { peek( dmaResponseQueue_in, ResponseMsg) { if (in_msg.Type == CoherenceResponseType:DMA_ACK) { - trigger(Event:DMA_Ack, makeLineAddress(in_msg.Address)); + trigger(Event:DMA_Ack, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE || - in_msg.Type == CoherenceResponseType:DATA) { - trigger(Event:Data, makeLineAddress(in_msg.Address)); + in_msg.Type == CoherenceResponseType:DATA) { + trigger(Event:Data, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:Inv_Ack, makeLineAddress(in_msg.Address)); + trigger(Event:Inv_Ack, makeLineAddress(in_msg.Address), + TBEs[makeLineAddress(in_msg.Address)]); } else { error("Invalid response type"); } @@ -115,7 +123,7 @@ machine(DMA, "DMA Controller") if (triggerQueue_in.isReady()) { peek(triggerQueue_in, TriggerMsg) { if (in_msg.Type == TriggerType:ALL_ACKS) { - trigger(Event:All_Acks, in_msg.Address); + trigger(Event:All_Acks, in_msg.Address, TBEs[in_msg.Address]); } else { error("Unexpected message"); } @@ -156,7 +164,8 @@ machine(DMA, "DMA Controller") } action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") { - if (TBEs[address].NumAcks == 0) { + assert(is_valid(tbe)); + if (tbe.NumAcks == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; out_msg.Type := TriggerType:ALL_ACKS; @@ -166,7 +175,8 @@ machine(DMA, "DMA Controller") action(u_updateAckCount, "u", desc="Update ack count") { peek(dmaResponseQueue_in, ResponseMsg) { - TBEs[address].NumAcks := TBEs[address].NumAcks - in_msg.Acks; + assert(is_valid(tbe)); + tbe.NumAcks := tbe.NumAcks - in_msg.Acks; } } @@ -193,20 +203,24 @@ machine(DMA, "DMA Controller") action(t_updateTBEData, "t", desc="Update TBE Data") { peek(dmaResponseQueue_in, ResponseMsg) { - TBEs[address].DataBlk := in_msg.DataBlk; + assert(is_valid(tbe)); + tbe.DataBlk := in_msg.DataBlk; } } action(d_dataCallbackFromTBE, "/d", desc="data callback with data from TBE") { - dma_sequencer.dataCallback(TBEs[address].DataBlk); + assert(is_valid(tbe)); + dma_sequencer.dataCallback(tbe.DataBlk); } action(v_allocateTBE, "v", desc="Allocate TBE entry") { TBEs.allocate(address); + set_tbe(TBEs[address]); } action(w_deallocateTBE, "w", desc="Deallocate TBE entry") { TBEs.deallocate(address); + unset_tbe(); } action(z_stall, "z", desc="dma is busy..stall") { diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm index a810a3e02..8cb45249e 100644 --- a/src/mem/protocol/MOESI_CMP_token-L1cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm @@ -171,6 +171,11 @@ machine(L1Cache, "Token protocol") int countStarvingForAddress(Address); int countReadStarvingForAddress(Address); } + + void set_cache_entry(AbstractCacheEntry b); + void unset_cache_entry(); + void set_tbe(TBE b); + void unset_tbe(); TBETable L1_TBEs, template_hack="<L1Cache_TBE>"; @@ -210,46 +215,39 @@ machine(L1Cache, "Token protocol") averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency; } - - Entry getCacheEntry(Address addr), return_by_ref="yes" { - if (L1DcacheMemory.isTagPresent(addr)) { - assert(L1IcacheMemory.isTagPresent(addr) == false); - return static_cast(Entry, L1DcacheMemory[addr]); - } else { - return static_cast(Entry, L1IcacheMemory[addr]); + Entry getCacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr)); + if(is_valid(L1Dcache_entry)) { + return L1Dcache_entry; } + + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory.lookup(addr)); + return L1Icache_entry; } - int getTokens(Address addr) { - if (L1DcacheMemory.isTagPresent(addr)) { - assert(L1IcacheMemory.isTagPresent(addr) == false); - return static_cast(Entry, L1DcacheMemory[addr]).Tokens; - } else if (L1IcacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L1IcacheMemory[addr]).Tokens; - } else { - return 0; - } + Entry getL1DCacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(addr)); + return L1Dcache_entry; } - void changePermission(Address addr, AccessPermission permission) { - if (L1DcacheMemory.isTagPresent(addr)) { - return L1DcacheMemory.changePermission(addr, permission); - } else { - return L1IcacheMemory.changePermission(addr, permission); - } + Entry getL1ICacheEntry(Address addr), return_by_pointer="yes" { + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory.lookup(addr)); + return L1Icache_entry; } - bool isCacheTagPresent(Address addr) { - return (L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr)); + int getTokens(Entry cache_entry) { + if (is_valid(cache_entry)) { + return cache_entry.Tokens; + } + return 0; } - State getState(Address addr) { - assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); + State getState(TBE tbe, Entry cache_entry, Address addr) { - if (L1_TBEs.isPresent(addr)) { - return L1_TBEs[addr].TBEState; - } else if (isCacheTagPresent(addr)) { - return getCacheEntry(addr).CacheState; + if (is_valid(tbe)) { + return tbe.TBEState; + } else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } else { if ((persistentTable.isLocked(addr) == true) && (persistentTable.findSmallest(addr) != machineID)) { // Not in cache, in persistent table, but this processor isn't highest priority @@ -260,31 +258,29 @@ machine(L1Cache, "Token protocol") } } - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); - if (L1_TBEs.isPresent(addr)) { + if (is_valid(tbe)) { assert(state != State:I); assert(state != State:S); assert(state != State:O); assert(state != State:MM); assert(state != State:M); - L1_TBEs[addr].TBEState := state; + tbe.TBEState := state; } - if (isCacheTagPresent(addr)) { + if (is_valid(cache_entry)) { // Make sure the token count is in range - assert(getCacheEntry(addr).Tokens >= 0); - assert(getCacheEntry(addr).Tokens <= max_tokens()); - assert(getCacheEntry(addr).Tokens != (max_tokens() / 2)); + assert(cache_entry.Tokens >= 0); + assert(cache_entry.Tokens <= max_tokens()); + assert(cache_entry.Tokens != (max_tokens() / 2)); if ((state == State:I_L) || (state == State:IM_L) || (state == State:IS_L)) { // Make sure we have no tokens in the "Invalid, locked" states - if (isCacheTagPresent(addr)) { - assert(getCacheEntry(addr).Tokens == 0); - } + assert(cache_entry.Tokens == 0); // Make sure the line is locked // assert(persistentTable.isLocked(addr)); @@ -294,8 +290,8 @@ machine(L1Cache, "Token protocol") } else if ((state == State:S_L) || (state == State:SM_L)) { - assert(getCacheEntry(addr).Tokens >= 1); - assert(getCacheEntry(addr).Tokens < (max_tokens() / 2)); + assert(cache_entry.Tokens >= 1); + assert(cache_entry.Tokens < (max_tokens() / 2)); // Make sure the line is locked... // assert(persistentTable.isLocked(addr)); @@ -321,30 +317,30 @@ machine(L1Cache, "Token protocol") // in M and E you have all the tokens if (state == State:MM || state == State:M || state == State:MM_W || state == State:M_W) { - assert(getCacheEntry(addr).Tokens == max_tokens()); + assert(cache_entry.Tokens == max_tokens()); } // in NP you have no tokens if (state == State:NP) { - assert(getCacheEntry(addr).Tokens == 0); + assert(cache_entry.Tokens == 0); } // You have at least one token in S-like states if (state == State:S || state == State:SM) { - assert(getCacheEntry(addr).Tokens > 0); + assert(cache_entry.Tokens > 0); } // You have at least half the token in O-like states if (state == State:O && state == State:OM) { - assert(getCacheEntry(addr).Tokens > (max_tokens() / 2)); + assert(cache_entry.Tokens > (max_tokens() / 2)); } - getCacheEntry(addr).CacheState := state; + cache_entry.CacheState := state; // Set permission if (state == State:MM || state == State:MM_W) { - changePermission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else if ((state == State:S) || (state == State:O) || (state == State:M) || @@ -353,9 +349,9 @@ machine(L1Cache, "Token protocol") (state == State:S_L) || (state == State:SM_L) || (state == State:OM)) { - changePermission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else { - changePermission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } } } @@ -418,6 +414,16 @@ machine(L1Cache, "Token protocol") persistentTable.markEntries(addr); } + void setExternalResponse(TBE tbe) { + assert(is_valid(tbe)); + tbe.ExternalResponse := true; + } + + bool IsAtomic(TBE tbe) { + assert(is_valid(tbe)); + return tbe.IsAtomic; + } + // ** OUT_PORTS ** out_port(persistentNetwork_out, PersistentMsg, persistentFromL1Cache); out_port(requestNetwork_out, RequestMsg, requestFromL1Cache); @@ -429,18 +435,24 @@ machine(L1Cache, "Token protocol") // Use Timer in_port(useTimerTable_in, Address, useTimerTable) { if (useTimerTable_in.isReady()) { - if (persistentTable.isLocked(useTimerTable.readyAddress()) && (persistentTable.findSmallest(useTimerTable.readyAddress()) != machineID)) { + TBE tbe := L1_TBEs[useTimerTable.readyAddress()]; + + if (persistentTable.isLocked(useTimerTable.readyAddress()) && + (persistentTable.findSmallest(useTimerTable.readyAddress()) != machineID)) { if (persistentTable.typeOfSmallest(useTimerTable.readyAddress()) == AccessType:Write) { - trigger(Event:Use_TimeoutStarverX, useTimerTable.readyAddress()); + trigger(Event:Use_TimeoutStarverX, useTimerTable.readyAddress(), + getCacheEntry(useTimerTable.readyAddress()), tbe); } else { - trigger(Event:Use_TimeoutStarverS, useTimerTable.readyAddress()); + trigger(Event:Use_TimeoutStarverS, useTimerTable.readyAddress(), + getCacheEntry(useTimerTable.readyAddress()), tbe); } } else { - assert(L1_TBEs.isPresent(useTimerTable.readyAddress())); - if (no_mig_atomic && L1_TBEs[useTimerTable.readyAddress()].IsAtomic) { - trigger(Event:Use_TimeoutNoStarvers_NoMig, useTimerTable.readyAddress()); + if (no_mig_atomic && IsAtomic(tbe)) { + trigger(Event:Use_TimeoutNoStarvers_NoMig, useTimerTable.readyAddress(), + getCacheEntry(useTimerTable.readyAddress()), tbe); } else { - trigger(Event:Use_TimeoutNoStarvers, useTimerTable.readyAddress()); + trigger(Event:Use_TimeoutNoStarvers, useTimerTable.readyAddress(), + getCacheEntry(useTimerTable.readyAddress()), tbe); } } } @@ -449,7 +461,9 @@ machine(L1Cache, "Token protocol") // Reissue Timer in_port(reissueTimerTable_in, Address, reissueTimerTable) { if (reissueTimerTable_in.isReady()) { - trigger(Event:Request_Timeout, reissueTimerTable.readyAddress()); + trigger(Event:Request_Timeout, reissueTimerTable.readyAddress(), + getCacheEntry(reissueTimerTable.readyAddress()), + L1_TBEs[reissueTimerTable.readyAddress()]); } } @@ -473,25 +487,33 @@ machine(L1Cache, "Token protocol") } // React to the message based on the current state of the table + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L1_TBEs[in_msg.Address]; + if (persistentTable.isLocked(in_msg.Address)) { if (persistentTable.findSmallest(in_msg.Address) == machineID) { // Our Own Lock - this processor is highest priority - trigger(Event:Own_Lock_or_Unlock, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock, in_msg.Address, + cache_entry, tbe); } else { if (persistentTable.typeOfSmallest(in_msg.Address) == AccessType:Read) { - if (getTokens(in_msg.Address) == 1 || - getTokens(in_msg.Address) == (max_tokens() / 2) + 1) { - trigger(Event:Persistent_GETS_Last_Token, in_msg.Address); + if (getTokens(cache_entry) == 1 || + getTokens(cache_entry) == (max_tokens() / 2) + 1) { + trigger(Event:Persistent_GETS_Last_Token, in_msg.Address, + cache_entry, tbe); } else { - trigger(Event:Persistent_GETS, in_msg.Address); + trigger(Event:Persistent_GETS, in_msg.Address, + cache_entry, tbe); } } else { - trigger(Event:Persistent_GETX, in_msg.Address); + trigger(Event:Persistent_GETX, in_msg.Address, + cache_entry, tbe); } } } else { // Unlock case - no entries in the table - trigger(Event:Own_Lock_or_Unlock, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock, in_msg.Address, + cache_entry, tbe); } } } @@ -503,29 +525,39 @@ machine(L1Cache, "Token protocol") if (requestNetwork_in.isReady()) { peek(requestNetwork_in, RequestMsg, block_on="Address") { assert(in_msg.Destination.isElement(machineID)); + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L1_TBEs[in_msg.Address]; + if (in_msg.Type == CoherenceRequestType:GETX) { if (in_msg.isLocal) { - trigger(Event:Transient_Local_GETX, in_msg.Address); + trigger(Event:Transient_Local_GETX, in_msg.Address, + cache_entry, tbe); } else { - trigger(Event:Transient_GETX, in_msg.Address); + trigger(Event:Transient_GETX, in_msg.Address, + cache_entry, tbe); } } else if (in_msg.Type == CoherenceRequestType:GETS) { - if (getTokens(in_msg.Address) == 1 || - getTokens(in_msg.Address) == (max_tokens() / 2) + 1) { + if (getTokens(cache_entry) == 1 || + getTokens(cache_entry) == (max_tokens() / 2) + 1) { if (in_msg.isLocal) { - trigger(Event:Transient_Local_GETS_Last_Token, in_msg.Address); + trigger(Event:Transient_Local_GETS_Last_Token, in_msg.Address, + cache_entry, tbe); } else { - trigger(Event:Transient_GETS_Last_Token, in_msg.Address); + trigger(Event:Transient_GETS_Last_Token, in_msg.Address, + cache_entry, tbe); } } else { if (in_msg.isLocal) { - trigger(Event:Transient_Local_GETS, in_msg.Address); + trigger(Event:Transient_Local_GETS, in_msg.Address, + cache_entry, tbe); } else { - trigger(Event:Transient_GETS, in_msg.Address); + trigger(Event:Transient_GETS, in_msg.Address, + cache_entry, tbe); } } } else { @@ -541,6 +573,9 @@ machine(L1Cache, "Token protocol") peek(responseNetwork_in, ResponseMsg, block_on="Address") { assert(in_msg.Destination.isElement(machineID)); + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := L1_TBEs[in_msg.Address]; + // Mark TBE flag if response received off-chip. Use this to update average latency estimate if ( machineIDToMachineType(in_msg.Sender) == MachineType:L2Cache ) { @@ -550,7 +585,7 @@ machine(L1Cache, "Token protocol") l2_select_num_bits)) { // came from an off-chip L2 cache - if (L1_TBEs.isPresent(in_msg.Address)) { + if (is_valid(tbe)) { // L1_TBEs[in_msg.Address].ExternalResponse := true; // profile_offchipL2_response(in_msg.Address); } @@ -559,14 +594,14 @@ machine(L1Cache, "Token protocol") // profile_onchipL2_response(in_msg.Address ); } } else if ( machineIDToMachineType(in_msg.Sender) == MachineType:Directory ) { - if (L1_TBEs.isPresent(in_msg.Address)) { - L1_TBEs[in_msg.Address].ExternalResponse := true; + if (is_valid(tbe)) { + setExternalResponse(tbe); // profile_memory_response( in_msg.Address); } } else if ( machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) { //if (isLocalProcessor(machineID, in_msg.Sender) == false) { - //if (L1_TBEs.isPresent(in_msg.Address)) { - // L1_TBEs[in_msg.Address].ExternalResponse := true; + //if (is_valid(tbe)) { + // tbe.ExternalResponse := true; // profile_offchipL1_response(in_msg.Address ); //} //} @@ -578,24 +613,24 @@ machine(L1Cache, "Token protocol") } - if (getTokens(in_msg.Address) + in_msg.Tokens != max_tokens()) { + if (getTokens(cache_entry) + in_msg.Tokens != max_tokens()) { if (in_msg.Type == CoherenceResponseType:ACK) { assert(in_msg.Tokens < (max_tokens() / 2)); - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) { - trigger(Event:Data_Owner, in_msg.Address); + trigger(Event:Data_Owner, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) { assert(in_msg.Tokens < (max_tokens() / 2)); - trigger(Event:Data_Shared, in_msg.Address); + trigger(Event:Data_Shared, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); } } else { if (in_msg.Type == CoherenceResponseType:ACK) { assert(in_msg.Tokens < (max_tokens() / 2)); - trigger(Event:Ack_All_Tokens, in_msg.Address); + trigger(Event:Ack_All_Tokens, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:DATA_SHARED) { - trigger(Event:Data_All_Tokens, in_msg.Address); + trigger(Event:Data_All_Tokens, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); } @@ -610,46 +645,65 @@ machine(L1Cache, "Token protocol") peek(mandatoryQueue_in, CacheMsg, block_on="LineAddress") { // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache + TBE tbe := L1_TBEs[in_msg.LineAddress]; + if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** // Check to see if it is in the OTHER L1 - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The block is in the wrong L1, try to write it to the L2 - trigger(Event:L1_Replacement, in_msg.LineAddress); + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Dcache_entry, tbe); } - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Icache_entry, tbe); } else { if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Icache_entry, tbe); } else { // No room in the L1, so we need to make room - trigger(Event:L1_Replacement, L1IcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_Replacement, + L1IcacheMemory.cacheProbe(in_msg.LineAddress), + getL1ICacheEntry(L1IcacheMemory.cacheProbe(in_msg.LineAddress)), + L1_TBEs[L1IcacheMemory.cacheProbe(in_msg.LineAddress)]); } } } else { // *** DATA ACCESS *** // Check to see if it is in the OTHER L1 - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + + if (is_valid(L1Icache_entry)) { // The block is in the wrong L1, try to write it to the L2 - trigger(Event:L1_Replacement, in_msg.LineAddress); + trigger(Event:L1_Replacement, in_msg.LineAddress, + L1Icache_entry, tbe); } - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Dcache_entry, tbe); } else { if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Dcache_entry, tbe); } else { // No room in the L1, so we need to make room - trigger(Event:L1_Replacement, L1DcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_Replacement, + L1DcacheMemory.cacheProbe(in_msg.LineAddress), + getL1DCacheEntry(L1DcacheMemory.cacheProbe(in_msg.LineAddress)), + L1_TBEs[L1DcacheMemory.cacheProbe(in_msg.LineAddress)]); } } } @@ -660,13 +714,14 @@ machine(L1Cache, "Token protocol") // ACTIONS action(a_issueReadRequest, "a", desc="Issue GETS") { - if (L1_TBEs[address].IssueCount == 0) { + assert(is_valid(tbe)); + if (tbe.IssueCount == 0) { // Update outstanding requests //profile_outstanding_request(outstandingRequests); outstandingRequests := outstandingRequests + 1; } - if (L1_TBEs[address].IssueCount >= retry_threshold) { + if (tbe.IssueCount >= retry_threshold) { // Issue a persistent request if possible if (okToIssueStarving(address, machineID) && (starving == false)) { enqueue(persistentNetwork_out, PersistentMsg, latency = l1_request_latency) { @@ -689,14 +744,14 @@ machine(L1Cache, "Token protocol") out_msg.Destination.add(map_Address_to_Directory(address)); out_msg.MessageSize := MessageSizeType:Persistent_Control; - out_msg.Prefetch := L1_TBEs[address].Prefetch; - out_msg.AccessMode := L1_TBEs[address].AccessMode; + out_msg.Prefetch := tbe.Prefetch; + out_msg.AccessMode := tbe.AccessMode; } markPersistentEntries(address); starving := true; - if (L1_TBEs[address].IssueCount == 0) { - //profile_persistent_prediction(address, L1_TBEs[address].AccessType); + if (tbe.IssueCount == 0) { + //profile_persistent_prediction(address, tbe.AccessType); } // Update outstanding requests @@ -704,9 +759,9 @@ machine(L1Cache, "Token protocol") outstandingPersistentRequests := outstandingPersistentRequests + 1; // Increment IssueCount - L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1; + tbe.IssueCount := tbe.IssueCount + 1; - L1_TBEs[address].WentPersistent := true; + tbe.WentPersistent := true; // Do not schedule a wakeup, a persistent requests will always complete } @@ -731,14 +786,14 @@ machine(L1Cache, "Token protocol") l2_select_low_bit, l2_select_num_bits)); - out_msg.RetryNum := L1_TBEs[address].IssueCount; - if (L1_TBEs[address].IssueCount == 0) { + out_msg.RetryNum := tbe.IssueCount; + if (tbe.IssueCount == 0) { out_msg.MessageSize := MessageSizeType:Request_Control; } else { out_msg.MessageSize := MessageSizeType:Reissue_Control; } - out_msg.Prefetch := L1_TBEs[address].Prefetch; - out_msg.AccessMode := L1_TBEs[address].AccessMode; + out_msg.Prefetch := tbe.Prefetch; + out_msg.AccessMode := tbe.AccessMode; } // send to other local L1s, with local bit set @@ -753,19 +808,19 @@ machine(L1Cache, "Token protocol") out_msg.Destination.broadcast(MachineType:L1Cache); out_msg.Destination.remove(machineID); - out_msg.RetryNum := L1_TBEs[address].IssueCount; + out_msg.RetryNum := tbe.IssueCount; out_msg.isLocal := true; - if (L1_TBEs[address].IssueCount == 0) { + if (tbe.IssueCount == 0) { out_msg.MessageSize := MessageSizeType:Broadcast_Control; } else { out_msg.MessageSize := MessageSizeType:Broadcast_Control; } - out_msg.Prefetch := L1_TBEs[address].Prefetch; - out_msg.AccessMode := L1_TBEs[address].AccessMode; + out_msg.Prefetch := tbe.Prefetch; + out_msg.AccessMode := tbe.AccessMode; } // Increment IssueCount - L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1; + tbe.IssueCount := tbe.IssueCount + 1; // Set a wakeup timer @@ -780,13 +835,14 @@ machine(L1Cache, "Token protocol") action(b_issueWriteRequest, "b", desc="Issue GETX") { - if (L1_TBEs[address].IssueCount == 0) { + assert(is_valid(tbe)); + if (tbe.IssueCount == 0) { // Update outstanding requests //profile_outstanding_request(outstandingRequests); outstandingRequests := outstandingRequests + 1; } - if (L1_TBEs[address].IssueCount >= retry_threshold) { + if (tbe.IssueCount >= retry_threshold) { // Issue a persistent request if possible if ( okToIssueStarving(address, machineID) && (starving == false)) { enqueue(persistentNetwork_out, PersistentMsg, latency = l1_request_latency) { @@ -809,8 +865,8 @@ machine(L1Cache, "Token protocol") out_msg.Destination.add(map_Address_to_Directory(address)); out_msg.MessageSize := MessageSizeType:Persistent_Control; - out_msg.Prefetch := L1_TBEs[address].Prefetch; - out_msg.AccessMode := L1_TBEs[address].AccessMode; + out_msg.Prefetch := tbe.Prefetch; + out_msg.AccessMode := tbe.AccessMode; } markPersistentEntries(address); starving := true; @@ -819,14 +875,14 @@ machine(L1Cache, "Token protocol") //profile_outstanding_persistent_request(outstandingPersistentRequests); outstandingPersistentRequests := outstandingPersistentRequests + 1; - if (L1_TBEs[address].IssueCount == 0) { - //profile_persistent_prediction(address, L1_TBEs[address].AccessType); + if (tbe.IssueCount == 0) { + //profile_persistent_prediction(address, tbe.AccessType); } // Increment IssueCount - L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1; + tbe.IssueCount := tbe.IssueCount + 1; - L1_TBEs[address].WentPersistent := true; + tbe.WentPersistent := true; // Do not schedule a wakeup, a persistent requests will always complete } @@ -853,15 +909,15 @@ machine(L1Cache, "Token protocol") l2_select_low_bit, l2_select_num_bits)); - out_msg.RetryNum := L1_TBEs[address].IssueCount; + out_msg.RetryNum := tbe.IssueCount; - if (L1_TBEs[address].IssueCount == 0) { + if (tbe.IssueCount == 0) { out_msg.MessageSize := MessageSizeType:Request_Control; } else { out_msg.MessageSize := MessageSizeType:Reissue_Control; } - out_msg.Prefetch := L1_TBEs[address].Prefetch; - out_msg.AccessMode := L1_TBEs[address].AccessMode; + out_msg.Prefetch := tbe.Prefetch; + out_msg.AccessMode := tbe.AccessMode; } // send to other local L1s too @@ -878,21 +934,21 @@ machine(L1Cache, "Token protocol") out_msg.Destination.broadcast(MachineType:L1Cache); out_msg.Destination.remove(machineID); - out_msg.RetryNum := L1_TBEs[address].IssueCount; - if (L1_TBEs[address].IssueCount == 0) { + out_msg.RetryNum := tbe.IssueCount; + if (tbe.IssueCount == 0) { out_msg.MessageSize := MessageSizeType:Broadcast_Control; } else { out_msg.MessageSize := MessageSizeType:Broadcast_Control; } - out_msg.Prefetch := L1_TBEs[address].Prefetch; - out_msg.AccessMode := L1_TBEs[address].AccessMode; + out_msg.Prefetch := tbe.Prefetch; + out_msg.AccessMode := tbe.AccessMode; } // Increment IssueCount - L1_TBEs[address].IssueCount := L1_TBEs[address].IssueCount + 1; + tbe.IssueCount := tbe.IssueCount + 1; DPRINTF(RubySlicc, "incremented issue count to %d\n", - L1_TBEs[address].IssueCount); + tbe.IssueCount); // Set a wakeup timer if (dynamic_timeout_enabled) { @@ -920,6 +976,7 @@ machine(L1Cache, "Token protocol") } action(c_ownedReplacement, "c", desc="Issue writeback") { + assert(is_valid(cache_entry)); enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Sender := machineID; @@ -929,21 +986,22 @@ machine(L1Cache, "Token protocol") l2_select_low_bit, l2_select_num_bits)); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.Type := CoherenceResponseType:WB_OWNED; // always send the data? out_msg.MessageSize := MessageSizeType:Writeback_Data; } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(cc_sharedReplacement, "\c", desc="Issue shared writeback") { // don't send writeback if replacing block with no tokens - assert (getCacheEntry(address).Tokens > 0); + assert(is_valid(cache_entry)); + assert (cache_entry.Tokens > 0); enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Sender := machineID; @@ -953,19 +1011,20 @@ machine(L1Cache, "Token protocol") l2_select_low_bit, l2_select_num_bits)); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // assert(getCacheEntry(address).Dirty == false); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + // assert(cache_entry.Dirty == false); out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:Writeback_Data; out_msg.Type := CoherenceResponseType:WB_SHARED_DATA; } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(tr_tokenReplacement, "tr", desc="Issue token writeback") { - if (getCacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Sender := machineID; @@ -975,9 +1034,9 @@ machine(L1Cache, "Token protocol") l2_select_low_bit, l2_select_num_bits)); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // assert(getCacheEntry(address).Dirty == false); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + // assert(cache_entry.Dirty == false); out_msg.Dirty := false; // always send the data? @@ -985,11 +1044,12 @@ machine(L1Cache, "Token protocol") out_msg.Type := CoherenceResponseType:WB_TOKENS; } } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(d_sendDataWithToken, "d", desc="Send data and a token from cache to requestor") { + assert(is_valid(cache_entry)); peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; @@ -997,8 +1057,8 @@ machine(L1Cache, "Token protocol") out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.Tokens := 1; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; out_msg.Dirty := false; if (in_msg.isLocal) { out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; @@ -1007,21 +1067,22 @@ machine(L1Cache, "Token protocol") } } } - getCacheEntry(address).Tokens := getCacheEntry(address).Tokens - 1; - assert(getCacheEntry(address).Tokens >= 1); + cache_entry.Tokens := cache_entry.Tokens - 1; + assert(cache_entry.Tokens >= 1); } action(d_sendDataWithNTokenIfAvail, "\dd", desc="Send data and a token from cache to requestor") { + assert(is_valid(cache_entry)); peek(requestNetwork_in, RequestMsg) { - if (getCacheEntry(address).Tokens > (N_tokens + (max_tokens() / 2))) { + if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_SHARED; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.Tokens := N_tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; out_msg.Dirty := false; if (in_msg.isLocal) { out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; @@ -1029,17 +1090,17 @@ machine(L1Cache, "Token protocol") out_msg.MessageSize := MessageSizeType:Response_Data; } } - getCacheEntry(address).Tokens := getCacheEntry(address).Tokens - N_tokens; + cache_entry.Tokens := cache_entry.Tokens - N_tokens; } - else if (getCacheEntry(address).Tokens > 1) { + else if (cache_entry.Tokens > 1) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_SHARED; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.Tokens := 1; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - // out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + // out_msg.Dirty := cache_entry.Dirty; out_msg.Dirty := false; if (in_msg.isLocal) { out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; @@ -1047,23 +1108,24 @@ machine(L1Cache, "Token protocol") out_msg.MessageSize := MessageSizeType:Response_Data; } } - getCacheEntry(address).Tokens := getCacheEntry(address).Tokens - 1; + cache_entry.Tokens := cache_entry.Tokens - 1; } } -// assert(getCacheEntry(address).Tokens >= 1); +// assert(cache_entry.Tokens >= 1); } action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") { peek(requestNetwork_in, RequestMsg) { + assert(is_valid(cache_entry)); enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - assert(getCacheEntry(address).Tokens > (max_tokens() / 2)); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + assert(cache_entry.Tokens > (max_tokens() / 2)); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; if (in_msg.isLocal) { out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; } else { @@ -1071,116 +1133,121 @@ machine(L1Cache, "Token protocol") } } } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") { // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - if (getCacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; - if (getCacheEntry(address).Tokens > (max_tokens() / 2)) { + if (cache_entry.Tokens > (max_tokens() / 2)) { out_msg.Type := CoherenceResponseType:DATA_OWNER; } else { out_msg.Type := CoherenceResponseType:ACK; } out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - assert(getCacheEntry(address).Tokens >= 1); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Control; } } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") { //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - assert(getCacheEntry(address).Tokens > 0); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens > 0); enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - assert(getCacheEntry(address).Tokens > (max_tokens() / 2)); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + assert(cache_entry.Tokens > (max_tokens() / 2)); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(f_sendAckWithAllButNorOneTokens, "f", desc="Send ack with all our tokens but one to starver.") { //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - assert(getCacheEntry(address).Tokens > 0); - if (getCacheEntry(address).Tokens > 1) { + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens > 0); + if (cache_entry.Tokens > 1) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; - if (getCacheEntry(address).Tokens > (max_tokens() / 2)) { + if (cache_entry.Tokens > (max_tokens() / 2)) { out_msg.Type := CoherenceResponseType:DATA_OWNER; } else { out_msg.Type := CoherenceResponseType:ACK; } out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - assert(getCacheEntry(address).Tokens >= 1); - if (getCacheEntry(address).Tokens > N_tokens) { - out_msg.Tokens := getCacheEntry(address).Tokens - N_tokens; + assert(cache_entry.Tokens >= 1); + if (cache_entry.Tokens > N_tokens) { + out_msg.Tokens := cache_entry.Tokens - N_tokens; } else { - out_msg.Tokens := getCacheEntry(address).Tokens - 1; + out_msg.Tokens := cache_entry.Tokens - 1; } - out_msg.DataBlk := getCacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Control; } } - if (getCacheEntry(address).Tokens > N_tokens) { - getCacheEntry(address).Tokens := N_tokens; + if (cache_entry.Tokens > N_tokens) { + cache_entry.Tokens := N_tokens; } else { - getCacheEntry(address).Tokens := 1; + cache_entry.Tokens := 1; } } action(ff_sendDataWithAllButNorOneTokens, "\f", desc="Send data and out tokens but one to starver") { //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - assert(getCacheEntry(address).Tokens > ((max_tokens() / 2) + 1)); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens > ((max_tokens() / 2) + 1)); enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - if (getCacheEntry(address).Tokens > (N_tokens + (max_tokens() / 2))) { - out_msg.Tokens := getCacheEntry(address).Tokens - N_tokens; + if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { + out_msg.Tokens := cache_entry.Tokens - N_tokens; } else { - out_msg.Tokens := getCacheEntry(address).Tokens - 1; + out_msg.Tokens := cache_entry.Tokens - 1; } assert(out_msg.Tokens > (max_tokens() / 2)); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } - if (getCacheEntry(address).Tokens > (N_tokens + (max_tokens() / 2))) { - getCacheEntry(address).Tokens := N_tokens; + if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { + cache_entry.Tokens := N_tokens; } else { - getCacheEntry(address).Tokens := 1; + cache_entry.Tokens := 1; } } action(fo_sendDataWithOwnerToken, "fo", desc="Send data and owner tokens") { - assert(getCacheEntry(address).Tokens == ((max_tokens() / 2) + 1)); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens == ((max_tokens() / 2) + 1)); enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - out_msg.Tokens := getCacheEntry(address).Tokens; + out_msg.Tokens := cache_entry.Tokens; assert(out_msg.Tokens > (max_tokens() / 2)); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(g_bounceResponseToStarver, "g", desc="Redirect response to starving processor") { @@ -1204,67 +1271,72 @@ machine(L1Cache, "Token protocol") action(h_load_hit, "h", desc="Notify sequencer the load completed.") { + assert(is_valid(cache_entry)); DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getCacheEntry(address).DataBlk); + address, cache_entry.DataBlk); sequencer.readCallback(address, GenericMachineType:L1Cache, - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } action(x_external_load_hit, "x", desc="Notify sequencer the load completed.") { + assert(is_valid(cache_entry)); DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getCacheEntry(address).DataBlk); + address, cache_entry.DataBlk); peek(responseNetwork_in, ResponseMsg) { sequencer.readCallback(address, getNondirectHitMachType(address, in_msg.Sender), - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } } action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") { + assert(is_valid(cache_entry)); DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getCacheEntry(address).DataBlk); + address, cache_entry.DataBlk); sequencer.writeCallback(address, GenericMachineType:L1Cache, - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); - getCacheEntry(address).Dirty := true; - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); + cache_entry.Dirty := true; + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); } action(xx_external_store_hit, "\x", desc="Notify sequencer that store completed.") { + assert(is_valid(cache_entry)); DPRINTF(RubySlicc, "Address: %s, Data Block: %s\n", - address, getCacheEntry(address).DataBlk); + address, cache_entry.DataBlk); peek(responseNetwork_in, ResponseMsg) { sequencer.writeCallback(address, getNondirectHitMachType(address, in_msg.Sender), - getCacheEntry(address).DataBlk); + cache_entry.DataBlk); } - getCacheEntry(address).Dirty := true; - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); + cache_entry.Dirty := true; + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); } action(i_allocateTBE, "i", desc="Allocate TBE") { check_allocate(L1_TBEs); L1_TBEs.allocate(address); - L1_TBEs[address].IssueCount := 0; + set_tbe(L1_TBEs[address]); + tbe.IssueCount := 0; peek(mandatoryQueue_in, CacheMsg) { - L1_TBEs[address].PC := in_msg.ProgramCounter; - L1_TBEs[address].AccessType := cache_request_type_to_access_type(in_msg.Type); + tbe.PC := in_msg.ProgramCounter; + tbe.AccessType := cache_request_type_to_access_type(in_msg.Type); if (in_msg.Type == CacheRequestType:ATOMIC) { - L1_TBEs[address].IsAtomic := true; + tbe.IsAtomic := true; } - L1_TBEs[address].Prefetch := in_msg.Prefetch; - L1_TBEs[address].AccessMode := in_msg.AccessMode; + tbe.Prefetch := in_msg.Prefetch; + tbe.AccessMode := in_msg.AccessMode; } - L1_TBEs[address].IssueTime := get_time(); + tbe.IssueTime := get_time(); } @@ -1317,21 +1389,23 @@ machine(L1Cache, "Token protocol") action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") { peek(responseNetwork_in, ResponseMsg) { + assert(is_valid(cache_entry)); assert(in_msg.Tokens != 0); DPRINTF(RubySlicc, "L1 received tokens for address: %s, tokens: %d\n", in_msg.Address, in_msg.Tokens); - getCacheEntry(address).Tokens := getCacheEntry(address).Tokens + in_msg.Tokens; - DPRINTF(RubySlicc, "%d\n", getCacheEntry(address).Tokens); + cache_entry.Tokens := cache_entry.Tokens + in_msg.Tokens; + DPRINTF(RubySlicc, "%d\n", cache_entry.Tokens); - if (getCacheEntry(address).Dirty == false && in_msg.Dirty) { - getCacheEntry(address).Dirty := true; + if (cache_entry.Dirty == false && in_msg.Dirty) { + cache_entry.Dirty := true; } } } action(s_deallocateTBE, "s", desc="Deallocate TBE") { - if (L1_TBEs[address].WentPersistent) { + assert(is_valid(tbe)); + if (tbe.WentPersistent) { // assert(starving == true); outstandingRequests := outstandingRequests - 1; enqueue(persistentNetwork_out, PersistentMsg, latency = l1_request_latency) { @@ -1359,74 +1433,80 @@ machine(L1Cache, "Token protocol") } // Update average latency - if (L1_TBEs[address].IssueCount <= 1) { - if (L1_TBEs[address].ExternalResponse == true) { - updateAverageLatencyEstimate(time_to_int(get_time()) - time_to_int(L1_TBEs[address].IssueTime)); + if (tbe.IssueCount <= 1) { + if (tbe.ExternalResponse == true) { + updateAverageLatencyEstimate(time_to_int(get_time()) - time_to_int(tbe.IssueTime)); } } // Profile - //if (L1_TBEs[address].WentPersistent) { - // profile_token_retry(address, L1_TBEs[address].AccessType, 2); + //if (tbe.WentPersistent) { + // profile_token_retry(address, tbe.AccessType, 2); //} //else { - // profile_token_retry(address, L1_TBEs[address].AccessType, 1); + // profile_token_retry(address, tbe.AccessType, 1); //} - //profile_token_retry(address, L1_TBEs[address].AccessType, L1_TBEs[address].IssueCount); + //profile_token_retry(address, tbe.AccessType, tbe.IssueCount); L1_TBEs.deallocate(address); + unset_tbe(); } action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") { - if (getCacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency = l1_response_latency) { out_msg.Address := address; - if (getCacheEntry(address).Tokens > (max_tokens() / 2)) { + if (cache_entry.Tokens > (max_tokens() / 2)) { out_msg.Type := CoherenceResponseType:DATA_OWNER; } else { out_msg.Type := CoherenceResponseType:ACK; } out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - assert(getCacheEntry(address).Tokens >= 1); - out_msg.Tokens := getCacheEntry(address).Tokens; - out_msg.DataBlk := getCacheEntry(address).DataBlk; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.MessageSize := MessageSizeType:Response_Control; } } } - getCacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(u_writeDataToCache, "u", desc="Write data to cache") { peek(responseNetwork_in, ResponseMsg) { - getCacheEntry(address).DataBlk := in_msg.DataBlk; - if (getCacheEntry(address).Dirty == false && in_msg.Dirty) { - getCacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + if (cache_entry.Dirty == false && in_msg.Dirty) { + cache_entry.Dirty := in_msg.Dirty; } } } action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") { - assert(getTokens(address) == 0); + assert(getTokens(cache_entry) == 0); if (L1DcacheMemory.isTagPresent(address)) { L1DcacheMemory.deallocate(address); } else { L1IcacheMemory.deallocate(address); } + unset_cache_entry(); } action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") { - if (L1DcacheMemory.isTagPresent(address) == false) { - L1DcacheMemory.allocate(address, new Entry); + if (is_valid(cache_entry)) { + } else { + set_cache_entry(L1DcacheMemory.allocate(address, new Entry)); } } action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") { - if (L1IcacheMemory.isTagPresent(address) == false) { - L1IcacheMemory.allocate(address, new Entry); + if (is_valid(cache_entry)) { + } else { + set_cache_entry(L1IcacheMemory.allocate(address, new Entry)); } } @@ -1442,7 +1522,8 @@ machine(L1Cache, "Token protocol") action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") { peek(responseNetwork_in, ResponseMsg) { - assert(getCacheEntry(address).DataBlk == in_msg.DataBlk); + assert(is_valid(cache_entry)); + assert(cache_entry.DataBlk == in_msg.DataBlk); } } diff --git a/src/mem/protocol/MOESI_CMP_token-L2cache.sm b/src/mem/protocol/MOESI_CMP_token-L2cache.sm index 3541da41b..c23f98f9a 100644 --- a/src/mem/protocol/MOESI_CMP_token-L2cache.sm +++ b/src/mem/protocol/MOESI_CMP_token-L2cache.sm @@ -148,35 +148,25 @@ machine(L2Cache, "Token protocol") PersistentTable persistentTable; PerfectCacheMemory localDirectory, template_hack="<L2Cache_DirEntry>"; - Entry getL2CacheEntry(Address addr), return_by_ref="yes" { - if (L2cacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L2cacheMemory[addr]); - } - assert(false); - return static_cast(Entry, L2cacheMemory[addr]); - } + void set_cache_entry(AbstractCacheEntry b); + void unset_cache_entry(); - int getTokens(Address addr) { - if (L2cacheMemory.isTagPresent(addr)) { - return getL2CacheEntry(addr).Tokens; + Entry getCacheEntry(Address address), return_by_pointer="yes" { + Entry cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address)); + return cache_entry; + } + + int getTokens(Entry cache_entry) { + if (is_valid(cache_entry)) { + return cache_entry.Tokens; } else { return 0; } } - void changePermission(Address addr, AccessPermission permission) { - if (L2cacheMemory.isTagPresent(addr)) { - return L2cacheMemory.changePermission(addr, permission); - } - } - - bool isCacheTagPresent(Address addr) { - return (L2cacheMemory.isTagPresent(addr) ); - } - - State getState(Address addr) { - if (isCacheTagPresent(addr)) { - return getL2CacheEntry(addr).CacheState; + State getState(Entry cache_entry, Address addr) { + if (is_valid(cache_entry)) { + return cache_entry.CacheState; } else if (persistentTable.isLocked(addr) == true) { return State:I_L; } else { @@ -184,57 +174,50 @@ machine(L2Cache, "Token protocol") } } - std::string getStateStr(Address addr) { - return L2Cache_State_to_string(getState(addr)); - } - - void setState(Address addr, State state) { - + void setState(Entry cache_entry, Address addr, State state) { - if (isCacheTagPresent(addr)) { + if (is_valid(cache_entry)) { // Make sure the token count is in range - assert(getL2CacheEntry(addr).Tokens >= 0); - assert(getL2CacheEntry(addr).Tokens <= max_tokens()); - assert(getL2CacheEntry(addr).Tokens != (max_tokens() / 2)); + assert(cache_entry.Tokens >= 0); + assert(cache_entry.Tokens <= max_tokens()); + assert(cache_entry.Tokens != (max_tokens() / 2)); // Make sure we have no tokens in L if ((state == State:I_L) ) { - if (isCacheTagPresent(addr)) { - assert(getL2CacheEntry(addr).Tokens == 0); - } + assert(cache_entry.Tokens == 0); } // in M and E you have all the tokens if (state == State:M ) { - assert(getL2CacheEntry(addr).Tokens == max_tokens()); + assert(cache_entry.Tokens == max_tokens()); } // in NP you have no tokens if (state == State:NP) { - assert(getL2CacheEntry(addr).Tokens == 0); + assert(cache_entry.Tokens == 0); } // You have at least one token in S-like states if (state == State:S ) { - assert(getL2CacheEntry(addr).Tokens > 0); + assert(cache_entry.Tokens > 0); } // You have at least half the token in O-like states if (state == State:O ) { - assert(getL2CacheEntry(addr).Tokens > (max_tokens() / 2)); + assert(cache_entry.Tokens > (max_tokens() / 2)); } - getL2CacheEntry(addr).CacheState := state; + cache_entry.CacheState := state; // Set permission if (state == State:I) { - changePermission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } else if (state == State:S || state == State:O ) { - changePermission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else if (state == State:M ) { - changePermission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else { - changePermission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } } } @@ -341,22 +324,24 @@ machine(L2Cache, "Token protocol") error("Unexpected message"); } + Entry cache_entry := getCacheEntry(in_msg.Address); // React to the message based on the current state of the table if (persistentTable.isLocked(in_msg.Address)) { if (persistentTable.typeOfSmallest(in_msg.Address) == AccessType:Read) { - if (getTokens(in_msg.Address) == 1 || - getTokens(in_msg.Address) == (max_tokens() / 2) + 1) { - trigger(Event:Persistent_GETS_Last_Token, in_msg.Address); + if (getTokens(cache_entry) == 1 || + getTokens(cache_entry) == (max_tokens() / 2) + 1) { + trigger(Event:Persistent_GETS_Last_Token, in_msg.Address, + cache_entry); } else { - trigger(Event:Persistent_GETS, in_msg.Address); + trigger(Event:Persistent_GETS, in_msg.Address, cache_entry); } } else { - trigger(Event:Persistent_GETX, in_msg.Address); + trigger(Event:Persistent_GETX, in_msg.Address, cache_entry); } } else { - trigger(Event:Own_Lock_or_Unlock, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock, in_msg.Address, cache_entry); } } } @@ -369,14 +354,16 @@ machine(L2Cache, "Token protocol") peek(requestNetwork_in, RequestMsg) { assert(in_msg.Destination.isElement(machineID)); + Entry cache_entry := getCacheEntry(in_msg.Address); if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:Transient_GETX, in_msg.Address); + trigger(Event:Transient_GETX, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceRequestType:GETS) { - if (L2cacheMemory.isTagPresent(in_msg.Address) && getL2CacheEntry(in_msg.Address).Tokens == 1) { - trigger(Event:Transient_GETS_Last_Token, in_msg.Address); + if (getTokens(cache_entry) == 1) { + trigger(Event:Transient_GETS_Last_Token, in_msg.Address, + cache_entry); } else { - trigger(Event:Transient_GETS, in_msg.Address); + trigger(Event:Transient_GETS, in_msg.Address, cache_entry); } } else { error("Unexpected message"); @@ -389,15 +376,16 @@ machine(L2Cache, "Token protocol") if (L1requestNetwork_in.isReady()) { peek(L1requestNetwork_in, RequestMsg) { assert(in_msg.Destination.isElement(machineID)); + Entry cache_entry := getCacheEntry(in_msg.Address); if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:L1_GETX, in_msg.Address); + trigger(Event:L1_GETX, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceRequestType:GETS) { - if (getTokens(in_msg.Address) == 1 || - getTokens(in_msg.Address) == (max_tokens() / 2) + 1) { - trigger(Event:L1_GETS_Last_Token, in_msg.Address); + if (getTokens(cache_entry) == 1 || + getTokens(cache_entry) == (max_tokens() / 2) + 1) { + trigger(Event:L1_GETS_Last_Token, in_msg.Address, cache_entry); } else { - trigger(Event:L1_GETS, in_msg.Address); + trigger(Event:L1_GETS, in_msg.Address, cache_entry); } } else { error("Unexpected message"); @@ -412,68 +400,80 @@ machine(L2Cache, "Token protocol") if (responseNetwork_in.isReady()) { peek(responseNetwork_in, ResponseMsg) { assert(in_msg.Destination.isElement(machineID)); - if (getTokens(in_msg.Address) + in_msg.Tokens != max_tokens()) { + Entry cache_entry := getCacheEntry(in_msg.Address); + + if (getTokens(cache_entry) + in_msg.Tokens != max_tokens()) { if (in_msg.Type == CoherenceResponseType:ACK) { assert(in_msg.Tokens < (max_tokens() / 2)); - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) { - trigger(Event:Data_Owner, in_msg.Address); + trigger(Event:Data_Owner, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) { - trigger(Event:Data_Shared, in_msg.Address); - } else if (in_msg.Type == CoherenceResponseType:WB_TOKENS || in_msg.Type == CoherenceResponseType:WB_OWNED || in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) { + trigger(Event:Data_Shared, in_msg.Address, cache_entry); + } else if (in_msg.Type == CoherenceResponseType:WB_TOKENS || + in_msg.Type == CoherenceResponseType:WB_OWNED || + in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) { - if (L2cacheMemory.cacheAvail(in_msg.Address) || L2cacheMemory.isTagPresent(in_msg.Address)) { + if (L2cacheMemory.cacheAvail(in_msg.Address) || is_valid(cache_entry)) { // either room is available or the block is already present if (in_msg.Type == CoherenceResponseType:WB_TOKENS) { assert(in_msg.Dirty == false); - trigger(Event:Writeback_Tokens, in_msg.Address); + trigger(Event:Writeback_Tokens, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) { assert(in_msg.Dirty == false); - trigger(Event:Writeback_Shared_Data, in_msg.Address); + trigger(Event:Writeback_Shared_Data, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceResponseType:WB_OWNED) { //assert(in_msg.Dirty == false); - trigger(Event:Writeback_Owned, in_msg.Address); + trigger(Event:Writeback_Owned, in_msg.Address, cache_entry); } } else { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address)); + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(in_msg.Address), + getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address))); } } else if (in_msg.Type == CoherenceResponseType:INV) { - trigger(Event:L1_INV, in_msg.Address); + trigger(Event:L1_INV, in_msg.Address, cache_entry); } else { error("Unexpected message"); } } else { if (in_msg.Type == CoherenceResponseType:ACK) { assert(in_msg.Tokens < (max_tokens() / 2)); - trigger(Event:Ack_All_Tokens, in_msg.Address); - } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:DATA_SHARED) { - trigger(Event:Data_All_Tokens, in_msg.Address); - } else if (in_msg.Type == CoherenceResponseType:WB_TOKENS || in_msg.Type == CoherenceResponseType:WB_OWNED || in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) { - if (L2cacheMemory.cacheAvail(in_msg.Address) || L2cacheMemory.isTagPresent(in_msg.Address)) { + trigger(Event:Ack_All_Tokens, in_msg.Address, cache_entry); + } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER || + in_msg.Type == CoherenceResponseType:DATA_SHARED) { + trigger(Event:Data_All_Tokens, in_msg.Address, cache_entry); + } else if (in_msg.Type == CoherenceResponseType:WB_TOKENS || + in_msg.Type == CoherenceResponseType:WB_OWNED || + in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) { + if (L2cacheMemory.cacheAvail(in_msg.Address) || is_valid(cache_entry)) { // either room is available or the block is already present if (in_msg.Type == CoherenceResponseType:WB_TOKENS) { assert(in_msg.Dirty == false); - assert( (getState(in_msg.Address) != State:NP) && (getState(in_msg.Address) != State:I) ); - trigger(Event:Writeback_All_Tokens, in_msg.Address); + assert( (getState(cache_entry, in_msg.Address) != State:NP) + && (getState(cache_entry, in_msg.Address) != State:I) ); + trigger(Event:Writeback_All_Tokens, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceResponseType:WB_SHARED_DATA) { assert(in_msg.Dirty == false); - trigger(Event:Writeback_All_Tokens, in_msg.Address); + trigger(Event:Writeback_All_Tokens, in_msg.Address, cache_entry); } else if (in_msg.Type == CoherenceResponseType:WB_OWNED) { - trigger(Event:Writeback_All_Tokens, in_msg.Address); + trigger(Event:Writeback_All_Tokens, in_msg.Address, cache_entry); } } else { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.Address)); + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(in_msg.Address), + getCacheEntry(L2cacheMemory.cacheProbe(in_msg.Address))); } } else if (in_msg.Type == CoherenceResponseType:INV) { - trigger(Event:L1_INV, in_msg.Address); + trigger(Event:L1_INV, in_msg.Address, cache_entry); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Unexpected message"); @@ -536,29 +536,31 @@ machine(L2Cache, "Token protocol") } action(c_cleanReplacement, "c", desc="Issue clean writeback") { - if (getL2CacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.Tokens := getL2CacheEntry(address).Tokens; + out_msg.Tokens := cache_entry.Tokens; out_msg.MessageSize := MessageSizeType:Writeback_Control; } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } } action(cc_dirtyReplacement, "\c", desc="Issue dirty writeback") { + assert(is_valid(cache_entry)); enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Sender := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.Tokens := getL2CacheEntry(address).Tokens; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; - if (getL2CacheEntry(address).Dirty) { + if (cache_entry.Dirty) { out_msg.MessageSize := MessageSizeType:Writeback_Data; out_msg.Type := CoherenceResponseType:DATA_OWNER; } else { @@ -566,23 +568,24 @@ machine(L2Cache, "Token protocol") out_msg.Type := CoherenceResponseType:ACK_OWNER; } } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(d_sendDataWithTokens, "d", desc="Send data and a token from cache to requestor") { peek(requestNetwork_in, RequestMsg) { - if (getL2CacheEntry(address).Tokens > (N_tokens + (max_tokens() / 2))) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_SHARED; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.Tokens := N_tokens; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:Response_Data; } - getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens - N_tokens; + cache_entry.Tokens := cache_entry.Tokens - N_tokens; } else { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { @@ -591,109 +594,115 @@ machine(L2Cache, "Token protocol") out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); out_msg.Tokens := 1; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:Response_Data; } - getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens - 1; + cache_entry.Tokens := cache_entry.Tokens - 1; } } } action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") { + assert(is_valid(cache_entry)); peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - assert(getL2CacheEntry(address).Tokens >= 1); - out_msg.Tokens := getL2CacheEntry(address).Tokens; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") { - if (getL2CacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - assert(getL2CacheEntry(address).Tokens >= 1); - out_msg.Tokens := getL2CacheEntry(address).Tokens; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; out_msg.MessageSize := MessageSizeType:Response_Control; } } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") { + assert(is_valid(cache_entry)); enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - assert(getL2CacheEntry(address).Tokens >= 1); - out_msg.Tokens := getL2CacheEntry(address).Tokens; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(f_sendAckWithAllButOneTokens, "f", desc="Send ack with all our tokens but one to starver.") { //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - assert(getL2CacheEntry(address).Tokens > 0); - if (getL2CacheEntry(address).Tokens > 1) { + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens > 0); + if (cache_entry.Tokens > 1) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - assert(getL2CacheEntry(address).Tokens >= 1); - out_msg.Tokens := getL2CacheEntry(address).Tokens - 1; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens - 1; out_msg.MessageSize := MessageSizeType:Response_Control; } } - getL2CacheEntry(address).Tokens := 1; + cache_entry.Tokens := 1; } action(ff_sendDataWithAllButOneTokens, "\f", desc="Send data and out tokens but one to starver") { //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - assert(getL2CacheEntry(address).Tokens > (max_tokens() / 2) + 1); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens > (max_tokens() / 2) + 1); enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - out_msg.Tokens := getL2CacheEntry(address).Tokens - 1; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.Tokens := cache_entry.Tokens - 1; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } - getL2CacheEntry(address).Tokens := 1; + cache_entry.Tokens := 1; } action(fa_sendDataWithAllTokens, "fa", desc="Send data and out tokens but one to starver") { //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself - assert(getL2CacheEntry(address).Tokens == (max_tokens() / 2) + 1); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens == (max_tokens() / 2) + 1); enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(persistentTable.findSmallest(address)); - out_msg.Tokens := getL2CacheEntry(address).Tokens; - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.Tokens := cache_entry.Tokens; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:Response_Data; } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } @@ -791,58 +800,60 @@ machine(L2Cache, "Token protocol") } } - action(k_dataFromL2CacheToL1Requestor, "k", desc="Send data and a token from cache to L1 requestor") { peek(L1requestNetwork_in, RequestMsg) { - assert(getL2CacheEntry(address).Tokens > 0); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens > 0); //enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_to_L1_RESPONSE_LATENCY") { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_SHARED; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data; out_msg.Tokens := 1; } - getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens - 1; + cache_entry.Tokens := cache_entry.Tokens - 1; } } action(k_dataOwnerFromL2CacheToL1Requestor, "\k", desc="Send data and a token from cache to L1 requestor") { peek(L1requestNetwork_in, RequestMsg) { - assert(getL2CacheEntry(address).Tokens == (max_tokens() / 2) + 1); + assert(is_valid(cache_entry)); + assert(cache_entry.Tokens == (max_tokens() / 2) + 1); enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data; - out_msg.Tokens := getL2CacheEntry(address).Tokens; + out_msg.Tokens := cache_entry.Tokens; } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } } action(k_dataAndAllTokensFromL2CacheToL1Requestor, "\kk", desc="Send data and a token from cache to L1 requestor") { peek(L1requestNetwork_in, RequestMsg) { -// assert(getL2CacheEntry(address).Tokens == max_tokens()); + assert(is_valid(cache_entry)); +// assert(cache_entry.Tokens == max_tokens()); //enqueue(responseIntraChipL2Network_out, ResponseMsg, latency="L2_to_L1_RESPONSE_LATENCY") { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_OWNER; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getL2CacheEntry(address).DataBlk; - out_msg.Dirty := getL2CacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; out_msg.MessageSize := MessageSizeType:ResponseL2hit_Data; //out_msg.Tokens := max_tokens(); - out_msg.Tokens := getL2CacheEntry(address).Tokens; + out_msg.Tokens := cache_entry.Tokens; } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } } @@ -865,13 +876,14 @@ machine(L2Cache, "Token protocol") action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") { peek(responseNetwork_in, ResponseMsg) { + assert(is_valid(cache_entry)); assert(in_msg.Tokens != 0); - getL2CacheEntry(address).Tokens := getL2CacheEntry(address).Tokens + in_msg.Tokens; + cache_entry.Tokens := cache_entry.Tokens + in_msg.Tokens; // this should ideally be in u_writeDataToCache, but Writeback_All_Tokens // may not trigger this action. if ( (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:WB_OWNED) && in_msg.Dirty) { - getL2CacheEntry(address).Dirty := true; + cache_entry.Dirty := true; } } } @@ -895,61 +907,65 @@ machine(L2Cache, "Token protocol") action(r_setMRU, "\rr", desc="manually set the MRU bit for cache line" ) { peek(L1requestNetwork_in, RequestMsg) { if ((machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache) && - (isCacheTagPresent(address))) { + (is_valid(cache_entry))) { L2cacheMemory.setMRU(address); } } } action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") { - if (getL2CacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { peek(requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - assert(getL2CacheEntry(address).Tokens >= 1); - out_msg.Tokens := getL2CacheEntry(address).Tokens; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; out_msg.MessageSize := MessageSizeType:Response_Control; } } } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(tt_sendLocalAckWithCollectedTokens, "tt", desc="Send ack with the tokens we've collected thus far.") { - if (getL2CacheEntry(address).Tokens > 0) { + assert(is_valid(cache_entry)); + if (cache_entry.Tokens > 0) { peek(L1requestNetwork_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=l2_response_latency) { out_msg.Address := address; out_msg.Type := CoherenceResponseType:ACK; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - assert(getL2CacheEntry(address).Tokens >= 1); - out_msg.Tokens := getL2CacheEntry(address).Tokens; + assert(cache_entry.Tokens >= 1); + out_msg.Tokens := cache_entry.Tokens; out_msg.MessageSize := MessageSizeType:Response_Control; } } } - getL2CacheEntry(address).Tokens := 0; + cache_entry.Tokens := 0; } action(u_writeDataToCache, "u", desc="Write data to cache") { peek(responseNetwork_in, ResponseMsg) { - getL2CacheEntry(address).DataBlk := in_msg.DataBlk; - if ((getL2CacheEntry(address).Dirty == false) && in_msg.Dirty) { - getL2CacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + if ((cache_entry.Dirty == false) && in_msg.Dirty) { + cache_entry.Dirty := in_msg.Dirty; } } } action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") { - L2cacheMemory.allocate(address, new Entry); + set_cache_entry(L2cacheMemory.allocate(address, new Entry)); } action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") { L2cacheMemory.deallocate(address); + unset_cache_entry(); } action(uu_profileMiss, "\u", desc="Profile the demand miss") { @@ -965,7 +981,8 @@ machine(L2Cache, "Token protocol") peek(responseNetwork_in, ResponseMsg) { if (in_msg.Type != CoherenceResponseType:ACK && in_msg.Type != CoherenceResponseType:WB_TOKENS) { - assert(getL2CacheEntry(address).DataBlk == in_msg.DataBlk); + assert(is_valid(cache_entry)); + assert(cache_entry.DataBlk == in_msg.DataBlk); } } } diff --git a/src/mem/protocol/MOESI_CMP_token-dir.sm b/src/mem/protocol/MOESI_CMP_token-dir.sm index 041d9b743..c77d46bbe 100644 --- a/src/mem/protocol/MOESI_CMP_token-dir.sm +++ b/src/mem/protocol/MOESI_CMP_token-dir.sm @@ -162,21 +162,24 @@ machine(Directory, "Token protocol") bool starving, default="false"; int l2_select_low_bit, default="RubySystem::getBlockSizeBits()"; + void set_tbe(TBE b); + void unset_tbe(); + Entry getDirectoryEntry(Address addr), return_by_ref="yes" { return static_cast(Entry, directory[addr]); } - State getState(Address addr) { - if (TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; + State getState(TBE tbe, Address addr) { + if (is_valid(tbe)) { + return tbe.TBEState; } else { return getDirectoryEntry(addr).DirectoryState; } } - void setState(Address addr, State state) { - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + void setState(TBE tbe, Address addr, State state) { + if (is_valid(tbe)) { + tbe.TBEState := state; } getDirectoryEntry(addr).DirectoryState := state; @@ -223,9 +226,9 @@ machine(Directory, "Token protocol") if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { if (in_msg.Type == MemoryRequestType:MEMORY_READ) { - trigger(Event:Memory_Data, in_msg.Address); + trigger(Event:Memory_Data, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { - trigger(Event:Memory_Ack, in_msg.Address); + trigger(Event:Memory_Ack, in_msg.Address, TBEs[in_msg.Address]); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Invalid message"); @@ -237,7 +240,8 @@ machine(Directory, "Token protocol") // Reissue Timer in_port(reissueTimerTable_in, Address, reissueTimerTable) { if (reissueTimerTable_in.isReady()) { - trigger(Event:Request_Timeout, reissueTimerTable.readyAddress()); + trigger(Event:Request_Timeout, reissueTimerTable.readyAddress(), + TBEs[reissueTimerTable.readyAddress()]); } } @@ -248,23 +252,29 @@ machine(Directory, "Token protocol") if (getDirectoryEntry(in_msg.Address).Tokens + in_msg.Tokens == max_tokens()) { if ((in_msg.Type == CoherenceResponseType:DATA_OWNER) || (in_msg.Type == CoherenceResponseType:DATA_SHARED)) { - trigger(Event:Data_All_Tokens, in_msg.Address); + trigger(Event:Data_All_Tokens, in_msg.Address, + TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:ACK_OWNER) { - trigger(Event:Ack_Owner_All_Tokens, in_msg.Address); + trigger(Event:Ack_Owner_All_Tokens, in_msg.Address, + TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:Ack_All_Tokens, in_msg.Address); + trigger(Event:Ack_All_Tokens, in_msg.Address, + TBEs[in_msg.Address]); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Invalid message"); } } else { if (in_msg.Type == CoherenceResponseType:DATA_OWNER) { - trigger(Event:Data_Owner, in_msg.Address); + trigger(Event:Data_Owner, in_msg.Address, + TBEs[in_msg.Address]); } else if ((in_msg.Type == CoherenceResponseType:ACK) || (in_msg.Type == CoherenceResponseType:DATA_SHARED)) { - trigger(Event:Tokens, in_msg.Address); + trigger(Event:Tokens, in_msg.Address, + TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceResponseType:ACK_OWNER) { - trigger(Event:Ack_Owner, in_msg.Address); + trigger(Event:Ack_Owner, in_msg.Address, + TBEs[in_msg.Address]); } else { DPRINTF(RubySlicc, "%s\n", in_msg.Type); error("Invalid message"); @@ -295,30 +305,39 @@ machine(Directory, "Token protocol") if (persistentTable.isLocked(in_msg.Address)) { if (persistentTable.findSmallest(in_msg.Address) == machineID) { if (getDirectoryEntry(in_msg.Address).Tokens > 0) { - trigger(Event:Own_Lock_or_Unlock_Tokens, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock_Tokens, in_msg.Address, + TBEs[in_msg.Address]); } else { - trigger(Event:Own_Lock_or_Unlock, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock, in_msg.Address, + TBEs[in_msg.Address]); } } else { - trigger(Event:Lockdown, in_msg.Address); // locked + // locked + trigger(Event:Lockdown, in_msg.Address, TBEs[in_msg.Address]); } } else { - trigger(Event:Unlockdown, in_msg.Address); // unlocked + // unlocked + trigger(Event:Unlockdown, in_msg.Address, TBEs[in_msg.Address]); } } else { if (persistentTable.findSmallest(in_msg.Address) == machineID) { if (getDirectoryEntry(in_msg.Address).Tokens > 0) { - trigger(Event:Own_Lock_or_Unlock_Tokens, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock_Tokens, in_msg.Address, + TBEs[in_msg.Address]); } else { - trigger(Event:Own_Lock_or_Unlock, in_msg.Address); + trigger(Event:Own_Lock_or_Unlock, in_msg.Address, + TBEs[in_msg.Address]); } } else if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) { - trigger(Event:Lockdown, in_msg.Address); // locked + // locked + trigger(Event:Lockdown, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) { - trigger(Event:Lockdown, in_msg.Address); // locked + // locked + trigger(Event:Lockdown, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) { - trigger(Event:Unlockdown, in_msg.Address); // unlocked + // unlocked + trigger(Event:Unlockdown, in_msg.Address, TBEs[in_msg.Address]); } else { error("Invalid message"); } @@ -332,9 +351,9 @@ machine(Directory, "Token protocol") peek(requestNetwork_in, RequestMsg) { assert(in_msg.Destination.isElement(machineID)); if (in_msg.Type == CoherenceRequestType:GETS) { - trigger(Event:GETS, in_msg.Address); + trigger(Event:GETS, in_msg.Address, TBEs[in_msg.Address]); } else if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:GETX, in_msg.Address); + trigger(Event:GETX, in_msg.Address, TBEs[in_msg.Address]); } else { error("Invalid message"); } @@ -346,12 +365,14 @@ machine(Directory, "Token protocol") if (dmaRequestQueue_in.isReady()) { peek(dmaRequestQueue_in, DMARequestMsg) { if (in_msg.Type == DMARequestType:READ) { - trigger(Event:DMA_READ, in_msg.LineAddress); + trigger(Event:DMA_READ, in_msg.LineAddress, TBEs[in_msg.LineAddress]); } else if (in_msg.Type == DMARequestType:WRITE) { if (getDirectoryEntry(in_msg.LineAddress).Tokens == max_tokens()) { - trigger(Event:DMA_WRITE_All_Tokens, in_msg.LineAddress); + trigger(Event:DMA_WRITE_All_Tokens, in_msg.LineAddress, + TBEs[in_msg.LineAddress]); } else { - trigger(Event:DMA_WRITE, in_msg.LineAddress); + trigger(Event:DMA_WRITE, in_msg.LineAddress, + TBEs[in_msg.LineAddress]); } } else { error("Invalid message"); @@ -408,7 +429,7 @@ machine(Directory, "Token protocol") markPersistentEntries(address); starving := true; - TBEs[address].WentPersistent := true; + tbe.WentPersistent := true; // Do not schedule a wakeup, a persistent requests will always complete } else { @@ -478,7 +499,7 @@ machine(Directory, "Token protocol") markPersistentEntries(address); starving := true; - TBEs[address].WentPersistent := true; + tbe.WentPersistent := true; // Do not schedule a wakeup, a persistent requests will always complete } else { @@ -574,7 +595,7 @@ machine(Directory, "Token protocol") out_msg.Destination.add(persistentTable.findSmallest(address)); assert(getDirectoryEntry(address).Tokens > 0); out_msg.Tokens := getDirectoryEntry(address).Tokens; - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.Dirty := false; out_msg.MessageSize := MessageSizeType:Response_Data; } @@ -634,9 +655,9 @@ machine(Directory, "Token protocol") out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; // first, initialize the data blk to the current version of system memory - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; // then add the dma write data - out_msg.DataBlk.copyPartial(TBEs[address].DmaDataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + out_msg.DataBlk.copyPartial(tbe.DmaDataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); DPRINTF(RubySlicc, "%s\n", out_msg); } } @@ -646,7 +667,7 @@ machine(Directory, "Token protocol") out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; // first, initialize the data blk to the current version of system memory - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; DPRINTF(RubySlicc, "%s\n", out_msg); } } @@ -654,17 +675,18 @@ machine(Directory, "Token protocol") action(vd_allocateDmaRequestInTBE, "vd", desc="Record Data in TBE") { peek(dmaRequestQueue_in, DMARequestMsg) { TBEs.allocate(address); - TBEs[address].DmaDataBlk := in_msg.DataBlk; - TBEs[address].PhysicalAddress := in_msg.PhysicalAddress; - TBEs[address].Len := in_msg.Len; - TBEs[address].DmaRequestor := in_msg.Requestor; - TBEs[address].WentPersistent := false; + set_tbe(TBEs[address]); + tbe.DmaDataBlk := in_msg.DataBlk; + tbe.PhysicalAddress := in_msg.PhysicalAddress; + tbe.Len := in_msg.Len; + tbe.DmaRequestor := in_msg.Requestor; + tbe.WentPersistent := false; } } action(s_deallocateTBE, "s", desc="Deallocate TBE") { - if (TBEs[address].WentPersistent) { + if (tbe.WentPersistent) { assert(starving == true); enqueue(persistentNetwork_out, PersistentMsg, latency = "1") { @@ -692,21 +714,22 @@ machine(Directory, "Token protocol") } TBEs.deallocate(address); + unset_tbe(); } action(rd_recordDataInTbe, "rd", desc="Record data in TBE") { peek(responseNetwork_in, ResponseMsg) { - TBEs[address].DataBlk := in_msg.DataBlk; + tbe.DataBlk := in_msg.DataBlk; } } action(cd_writeCleanDataToTbe, "cd", desc="Write clean memory data to TBE") { - TBEs[address].DataBlk := getDirectoryEntry(address).DataBlk; + tbe.DataBlk := getDirectoryEntry(address).DataBlk; } action(dwt_writeDmaDataFromTBE, "dwt", desc="DMA Write data to memory from TBE") { - getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk; - getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DmaDataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + getDirectoryEntry(address).DataBlk := tbe.DataBlk; + getDirectoryEntry(address).DataBlk.copyPartial(tbe.DmaDataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); } action(f_incrementTokens, "f", desc="Increment the number of tokens we're tracking") { @@ -837,7 +860,7 @@ machine(Directory, "Token protocol") out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:ACK; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Writeback_Control; } } @@ -853,7 +876,7 @@ machine(Directory, "Token protocol") // split it up if need be // out_msg.DataBlk := in_msg.DataBlk; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -870,7 +893,7 @@ machine(Directory, "Token protocol") // split it up if need be // out_msg.DataBlk := in_msg.DataBlk; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Response_Data; } } diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm index 6e62c7472..659979ddf 100644 --- a/src/mem/protocol/MOESI_hammer-cache.sm +++ b/src/mem/protocol/MOESI_hammer-cache.sm @@ -153,59 +153,66 @@ machine(L1Cache, "AMD Hammer-like protocol") TBETable TBEs, template_hack="<L1Cache_TBE>"; - Entry getCacheEntry(Address addr), return_by_ref="yes" { - if (L2cacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L2cacheMemory[addr]); - } else if (L1DcacheMemory.isTagPresent(addr)) { - return static_cast(Entry, L1DcacheMemory[addr]); - } else { - return static_cast(Entry, L1IcacheMemory[addr]); + void set_cache_entry(AbstractCacheEntry b); + void unset_cache_entry(); + void set_tbe(TBE b); + void unset_tbe(); + + Entry getCacheEntry(Address address), return_by_pointer="yes" { + Entry L2cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address)); + if(is_valid(L2cache_entry)) { + return L2cache_entry; } - } - void changePermission(Address addr, AccessPermission permission) { - if (L2cacheMemory.isTagPresent(addr)) { - return L2cacheMemory.changePermission(addr, permission); - } else if (L1DcacheMemory.isTagPresent(addr)) { - return L1DcacheMemory.changePermission(addr, permission); - } else { - return L1IcacheMemory.changePermission(addr, permission); + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(address)); + if(is_valid(L1Dcache_entry)) { + return L1Dcache_entry; } + + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory.lookup(address)); + return L1Icache_entry; } - bool isCacheTagPresent(Address addr) { - return (L2cacheMemory.isTagPresent(addr) || L1DcacheMemory.isTagPresent(addr) || L1IcacheMemory.isTagPresent(addr)); + Entry getL2CacheEntry(Address address), return_by_pointer="yes" { + Entry L2cache_entry := static_cast(Entry, "pointer", L2cacheMemory.lookup(address)); + return L2cache_entry; } - State getState(Address addr) { - assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); - assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false); - assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false); + Entry getL1DCacheEntry(Address address), return_by_pointer="yes" { + Entry L1Dcache_entry := static_cast(Entry, "pointer", L1DcacheMemory.lookup(address)); + return L1Dcache_entry; + } + + Entry getL1ICacheEntry(Address address), return_by_pointer="yes" { + Entry L1Icache_entry := static_cast(Entry, "pointer", L1IcacheMemory.lookup(address)); + return L1Icache_entry; + } - if(TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; - } else if (isCacheTagPresent(addr)) { - return getCacheEntry(addr).CacheState; + State getState(TBE tbe, Entry cache_entry, Address addr) { + if(is_valid(tbe)) { + return tbe.TBEState; + } else if (is_valid(cache_entry)) { + return cache_entry.CacheState; } return State:I; } - void setState(Address addr, State state) { + void setState(TBE tbe, Entry cache_entry, Address addr, State state) { assert((L1DcacheMemory.isTagPresent(addr) && L1IcacheMemory.isTagPresent(addr)) == false); assert((L1IcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false); assert((L1DcacheMemory.isTagPresent(addr) && L2cacheMemory.isTagPresent(addr)) == false); - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + if (is_valid(tbe)) { + tbe.TBEState := state; } - if (isCacheTagPresent(addr)) { - getCacheEntry(addr).CacheState := state; + if (is_valid(cache_entry)) { + cache_entry.CacheState := state; // Set permission if ((state == State:MM) || (state == State:MM_W)) { - changePermission(addr, AccessPermission:Read_Write); + cache_entry.changePermission(AccessPermission:Read_Write); } else if (state == State:S || state == State:O || state == State:M || @@ -214,9 +221,9 @@ machine(L1Cache, "AMD Hammer-like protocol") state == State:ISM || state == State:OM || state == State:SS) { - changePermission(addr, AccessPermission:Read_Only); + cache_entry.changePermission(AccessPermission:Read_Only); } else { - changePermission(addr, AccessPermission:Invalid); + cache_entry.changePermission(AccessPermission:Invalid); } } } @@ -244,15 +251,20 @@ machine(L1Cache, "AMD Hammer-like protocol") } } - GenericMachineType testAndClearLocalHit(Address addr) { - if (getCacheEntry(addr).FromL2) { - getCacheEntry(addr).FromL2 := false; + GenericMachineType testAndClearLocalHit(Entry cache_entry) { + if (is_valid(cache_entry) && cache_entry.FromL2) { + cache_entry.FromL2 := false; return GenericMachineType:L2Cache; } else { return GenericMachineType:L1Cache; } } + bool IsAtomicAccessed(Entry cache_entry) { + assert(is_valid(cache_entry)); + return cache_entry.AtomicAccessed; + } + MessageBuffer triggerQueue, ordered="true"; // ** OUT_PORTS ** @@ -268,12 +280,16 @@ machine(L1Cache, "AMD Hammer-like protocol") in_port(triggerQueue_in, TriggerMsg, triggerQueue) { if (triggerQueue_in.isReady()) { peek(triggerQueue_in, TriggerMsg) { + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; + if (in_msg.Type == TriggerType:L2_to_L1) { - trigger(Event:Complete_L2_to_L1, in_msg.Address); + trigger(Event:Complete_L2_to_L1, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == TriggerType:ALL_ACKS) { - trigger(Event:All_acks, in_msg.Address); + trigger(Event:All_acks, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == TriggerType:ALL_ACKS_NO_SHARERS) { - trigger(Event:All_acks_no_sharers, in_msg.Address); + trigger(Event:All_acks_no_sharers, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); } @@ -287,30 +303,34 @@ machine(L1Cache, "AMD Hammer-like protocol") in_port(forwardToCache_in, RequestMsg, forwardToCache) { if (forwardToCache_in.isReady()) { peek(forwardToCache_in, RequestMsg, block_on="Address") { + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; + if (in_msg.Type == CoherenceRequestType:GETX) { - trigger(Event:Other_GETX, in_msg.Address); + trigger(Event:Other_GETX, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:MERGED_GETS) { - trigger(Event:Merged_GETS, in_msg.Address); + trigger(Event:Merged_GETS, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:GETS) { if (machineCount(MachineType:L1Cache) > 1) { - if (isCacheTagPresent(in_msg.Address)) { - if (getCacheEntry(in_msg.Address).AtomicAccessed && no_mig_atomic) { - trigger(Event:Other_GETS_No_Mig, in_msg.Address); + if (is_valid(cache_entry)) { + if (IsAtomicAccessed(cache_entry) && no_mig_atomic) { + trigger(Event:Other_GETS_No_Mig, in_msg.Address, cache_entry, tbe); } else { - trigger(Event:Other_GETS, in_msg.Address); + trigger(Event:Other_GETS, in_msg.Address, cache_entry, tbe); } } else { - trigger(Event:Other_GETS, in_msg.Address); + trigger(Event:Other_GETS, in_msg.Address, cache_entry, tbe); } } else { - trigger(Event:NC_DMA_GETS, in_msg.Address); + trigger(Event:NC_DMA_GETS, in_msg.Address, cache_entry, tbe); } } else if (in_msg.Type == CoherenceRequestType:INV) { - trigger(Event:Invalidate, in_msg.Address); + trigger(Event:Invalidate, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:WB_ACK) { - trigger(Event:Writeback_Ack, in_msg.Address); + trigger(Event:Writeback_Ack, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceRequestType:WB_NACK) { - trigger(Event:Writeback_Nack, in_msg.Address); + trigger(Event:Writeback_Nack, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); } @@ -322,16 +342,20 @@ machine(L1Cache, "AMD Hammer-like protocol") in_port(responseToCache_in, ResponseMsg, responseToCache) { if (responseToCache_in.isReady()) { peek(responseToCache_in, ResponseMsg, block_on="Address") { + + Entry cache_entry := getCacheEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; + if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:ACK_SHARED) { - trigger(Event:Shared_Ack, in_msg.Address); + trigger(Event:Shared_Ack, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) { - trigger(Event:Shared_Data, in_msg.Address); + trigger(Event:Shared_Data, in_msg.Address, cache_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Exclusive_Data, in_msg.Address); + trigger(Event:Exclusive_Data, in_msg.Address, cache_entry, tbe); } else { error("Unexpected message"); } @@ -347,41 +371,58 @@ machine(L1Cache, "AMD Hammer-like protocol") peek(mandatoryQueue_in, CacheMsg, block_on="LineAddress") { // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache + TBE tbe := TBEs[in_msg.LineAddress]; if (in_msg.Type == CacheRequestType:IFETCH) { // ** INSTRUCTION ACCESS *** // Check to see if it is in the OTHER L1 - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The block is in the wrong L1, try to write it to the L2 if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) { - trigger(Event:L1_to_L2, in_msg.LineAddress); + trigger(Event:L1_to_L2, in_msg.LineAddress, L1Dcache_entry, tbe); } else { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(in_msg.LineAddress), + getL2CacheEntry(L2cacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L2cacheMemory.cacheProbe(in_msg.LineAddress)]); } } - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Icache_entry, tbe); } else { if (L1IcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 - if (L2cacheMemory.isTagPresent(in_msg.LineAddress)) { + + Entry L2cache_entry := getL2CacheEntry(in_msg.LineAddress); + if (is_valid(L2cache_entry)) { // L2 has it (maybe not with the right permissions) - trigger(Event:Trigger_L2_to_L1I, in_msg.LineAddress); + trigger(Event:Trigger_L2_to_L1I, in_msg.LineAddress, + L2cache_entry, tbe); } else { // We have room, the L2 doesn't have it, so the L1 fetches the line - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Icache_entry, tbe); } } else { // No room in the L1, so we need to make room if (L2cacheMemory.cacheAvail(L1IcacheMemory.cacheProbe(in_msg.LineAddress))) { // The L2 has room, so we move the line from the L1 to the L2 - trigger(Event:L1_to_L2, L1IcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_to_L2, + L1IcacheMemory.cacheProbe(in_msg.LineAddress), + getL1ICacheEntry(L1IcacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L1IcacheMemory.cacheProbe(in_msg.LineAddress)]); } else { // The L2 does not have room, so we replace a line from the L2 - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.LineAddress))); + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.LineAddress)), + getL2CacheEntry(L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.LineAddress))), + TBEs[L2cacheMemory.cacheProbe(L1IcacheMemory.cacheProbe(in_msg.LineAddress))]); } } } @@ -389,36 +430,51 @@ machine(L1Cache, "AMD Hammer-like protocol") // *** DATA ACCESS *** // Check to see if it is in the OTHER L1 - if (L1IcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); + if (is_valid(L1Icache_entry)) { // The block is in the wrong L1, try to write it to the L2 if (L2cacheMemory.cacheAvail(in_msg.LineAddress)) { - trigger(Event:L1_to_L2, in_msg.LineAddress); + trigger(Event:L1_to_L2, in_msg.LineAddress, L1Icache_entry, tbe); } else { - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(in_msg.LineAddress), + getL2CacheEntry(L2cacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L2cacheMemory.cacheProbe(in_msg.LineAddress)]); } } - if (L1DcacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); + if (is_valid(L1Dcache_entry)) { // The tag matches for the L1, so the L1 fetches the line. We know it can't be in the L2 due to exclusion - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Dcache_entry, tbe); } else { if (L1DcacheMemory.cacheAvail(in_msg.LineAddress)) { // L1 does't have the line, but we have space for it in the L1 - if (L2cacheMemory.isTagPresent(in_msg.LineAddress)) { + Entry L2cache_entry := getL2CacheEntry(in_msg.LineAddress); + if (is_valid(L2cache_entry)) { // L2 has it (maybe not with the right permissions) - trigger(Event:Trigger_L2_to_L1D, in_msg.LineAddress); + trigger(Event:Trigger_L2_to_L1D, in_msg.LineAddress, + L2cache_entry, tbe); } else { // We have room, the L2 doesn't have it, so the L1 fetches the line - trigger(mandatory_request_type_to_event(in_msg.Type), in_msg.LineAddress); + trigger(mandatory_request_type_to_event(in_msg.Type), + in_msg.LineAddress, L1Dcache_entry, tbe); } } else { // No room in the L1, so we need to make room if (L2cacheMemory.cacheAvail(L1DcacheMemory.cacheProbe(in_msg.LineAddress))) { // The L2 has room, so we move the line from the L1 to the L2 - trigger(Event:L1_to_L2, L1DcacheMemory.cacheProbe(in_msg.LineAddress)); + trigger(Event:L1_to_L2, + L1DcacheMemory.cacheProbe(in_msg.LineAddress), + getL1DCacheEntry(L1DcacheMemory.cacheProbe(in_msg.LineAddress)), + TBEs[L1DcacheMemory.cacheProbe(in_msg.LineAddress)]); } else { // The L2 does not have room, so we replace a line from the L2 - trigger(Event:L2_Replacement, L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.LineAddress))); + trigger(Event:L2_Replacement, + L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.LineAddress)), + getL2CacheEntry(L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.LineAddress))), + TBEs[L2cacheMemory.cacheProbe(L1DcacheMemory.cacheProbe(in_msg.LineAddress))]); } } } @@ -431,37 +487,40 @@ machine(L1Cache, "AMD Hammer-like protocol") action(a_issueGETS, "a", desc="Issue GETS") { enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:GETS; out_msg.Requestor := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); out_msg.MessageSize := MessageSizeType:Request_Control; out_msg.InitialRequestTime := get_time(); - TBEs[address].NumPendingMsgs := machineCount(MachineType:L1Cache); // One from each other cache (n-1) plus the memory (+1) + tbe.NumPendingMsgs := machineCount(MachineType:L1Cache); // One from each other cache (n-1) plus the memory (+1) } } action(b_issueGETX, "b", desc="Issue GETX") { enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:GETX; out_msg.Requestor := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); out_msg.MessageSize := MessageSizeType:Request_Control; out_msg.InitialRequestTime := get_time(); - TBEs[address].NumPendingMsgs := machineCount(MachineType:L1Cache); // One from each other cache (n-1) plus the memory (+1) + tbe.NumPendingMsgs := machineCount(MachineType:L1Cache); // One from each other cache (n-1) plus the memory (+1) } } action(c_sendExclusiveData, "c", desc="Send exclusive data from cache to requestor") { peek(forwardToCache_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; if (in_msg.DirectedProbe) { out_msg.Acks := machineCount(MachineType:L1Cache); } else { @@ -487,12 +546,13 @@ machine(L1Cache, "AMD Hammer-like protocol") action(e_sendData, "e", desc="Send data from cache to requestor") { peek(forwardToCache_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getCacheEntry(address).DataBlk; - out_msg.Dirty := getCacheEntry(address).Dirty; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; if (in_msg.DirectedProbe) { out_msg.Acks := machineCount(MachineType:L1Cache); } else { @@ -508,13 +568,14 @@ machine(L1Cache, "AMD Hammer-like protocol") action(ee_sendDataShared, "\e", desc="Send data from cache to requestor, keep a shared copy") { peek(forwardToCache_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_SHARED; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); - out_msg.DataBlk := getCacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; DPRINTF(RubySlicc, "%s\n", out_msg.DataBlk); - out_msg.Dirty := getCacheEntry(address).Dirty; if (in_msg.DirectedProbe) { out_msg.Acks := machineCount(MachineType:L1Cache); } else { @@ -530,13 +591,14 @@ machine(L1Cache, "AMD Hammer-like protocol") action(em_sendDataSharedMultiple, "em", desc="Send data from cache to all requestors") { peek(forwardToCache_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA_SHARED; out_msg.Sender := machineID; out_msg.Destination := in_msg.MergedRequestors; - out_msg.DataBlk := getCacheEntry(address).DataBlk; + out_msg.DataBlk := cache_entry.DataBlk; + out_msg.Dirty := cache_entry.Dirty; DPRINTF(RubySlicc, "%s\n", out_msg.DataBlk); - out_msg.Dirty := getCacheEntry(address).Dirty; out_msg.Acks := machineCount(MachineType:L1Cache); out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.InitialRequestTime := in_msg.InitialRequestTime; @@ -599,87 +661,91 @@ machine(L1Cache, "AMD Hammer-like protocol") action(gs_sendUnblockS, "gs", desc="Send unblock to memory and indicate S state") { enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:UNBLOCKS; out_msg.Sender := machineID; - out_msg.CurOwner := TBEs[address].CurOwner; + out_msg.CurOwner := tbe.CurOwner; out_msg.Destination.add(map_Address_to_Directory(address)); out_msg.MessageSize := MessageSizeType:Unblock_Control; } } action(h_load_hit, "h", desc="Notify sequencer the load completed.") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); - - sequencer.readCallback(address, - testAndClearLocalHit(address), - getCacheEntry(address).DataBlk); - + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); + sequencer.readCallback(address, testAndClearLocalHit(cache_entry), + cache_entry.DataBlk); } action(hx_external_load_hit, "hx", desc="load required external msgs") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + assert(is_valid(tbe)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); peek(responseToCache_in, ResponseMsg) { sequencer.readCallback(address, getNondirectHitMachType(in_msg.Address, in_msg.Sender), - getCacheEntry(address).DataBlk, - TBEs[address].InitialRequestTime, - TBEs[address].ForwardRequestTime, - TBEs[address].FirstResponseTime); - + cache_entry.DataBlk, + tbe.InitialRequestTime, + tbe.ForwardRequestTime, + tbe.FirstResponseTime); } } action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); peek(mandatoryQueue_in, CacheMsg) { - sequencer.writeCallback(address, - testAndClearLocalHit(address), - getCacheEntry(address).DataBlk); + sequencer.writeCallback(address, testAndClearLocalHit(cache_entry), + cache_entry.DataBlk); - getCacheEntry(address).Dirty := true; + cache_entry.Dirty := true; if (in_msg.Type == CacheRequestType:ATOMIC) { - getCacheEntry(address).AtomicAccessed := true; + cache_entry.AtomicAccessed := true; } } } action(sx_external_store_hit, "sx", desc="store required external msgs.") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + assert(is_valid(tbe)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); peek(responseToCache_in, ResponseMsg) { sequencer.writeCallback(address, getNondirectHitMachType(address, in_msg.Sender), - getCacheEntry(address).DataBlk, - TBEs[address].InitialRequestTime, - TBEs[address].ForwardRequestTime, - TBEs[address].FirstResponseTime); - + cache_entry.DataBlk, + tbe.InitialRequestTime, + tbe.ForwardRequestTime, + tbe.FirstResponseTime); } - getCacheEntry(address).Dirty := true; + cache_entry.Dirty := true; } action(sxt_trig_ext_store_hit, "sxt", desc="store required external msgs.") { - DPRINTF(RubySlicc, "%s\n", getCacheEntry(address).DataBlk); + assert(is_valid(cache_entry)); + assert(is_valid(tbe)); + DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); sequencer.writeCallback(address, - getNondirectHitMachType(address, - TBEs[address].LastResponder), - getCacheEntry(address).DataBlk, - TBEs[address].InitialRequestTime, - TBEs[address].ForwardRequestTime, - TBEs[address].FirstResponseTime); + getNondirectHitMachType(address, tbe.LastResponder), + cache_entry.DataBlk, + tbe.InitialRequestTime, + tbe.ForwardRequestTime, + tbe.FirstResponseTime); - getCacheEntry(address).Dirty := true; + cache_entry.Dirty := true; } action(i_allocateTBE, "i", desc="Allocate TBE") { check_allocate(TBEs); + assert(is_valid(cache_entry)); TBEs.allocate(address); - TBEs[address].DataBlk := getCacheEntry(address).DataBlk; // Data only used for writebacks - TBEs[address].Dirty := getCacheEntry(address).Dirty; - TBEs[address].Sharers := false; + set_tbe(TBEs[address]); + tbe.DataBlk := cache_entry.DataBlk; // Data only used for writebacks + tbe.Dirty := cache_entry.Dirty; + tbe.Sharers := false; } action(j_popTriggerQueue, "j", desc="Pop trigger queue.") { @@ -695,43 +761,49 @@ machine(L1Cache, "AMD Hammer-like protocol") } action(hp_copyFromTBEToL2, "li", desc="Copy data from TBE to L2 cache entry.") { - getCacheEntry(address).Dirty := TBEs[address].Dirty; - getCacheEntry(address).DataBlk := TBEs[address].DataBlk; + assert(is_valid(cache_entry)); + assert(is_valid(tbe)); + cache_entry.Dirty := tbe.Dirty; + cache_entry.DataBlk := tbe.DataBlk; } action(nb_copyFromTBEToL1, "fu", desc="Copy data from TBE to L1 cache entry.") { - getCacheEntry(address).Dirty := TBEs[address].Dirty; - getCacheEntry(address).DataBlk := TBEs[address].DataBlk; - getCacheEntry(address).FromL2 := true; + assert(is_valid(cache_entry)); + assert(is_valid(tbe)); + cache_entry.Dirty := tbe.Dirty; + cache_entry.DataBlk := tbe.DataBlk; + cache_entry.FromL2 := true; } action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") { peek(responseToCache_in, ResponseMsg) { assert(in_msg.Acks > 0); - DPRINTF(RubySlicc, "%d\n", TBEs[address].NumPendingMsgs); - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - in_msg.Acks; - DPRINTF(RubySlicc, "%d\n", TBEs[address].NumPendingMsgs); - TBEs[address].LastResponder := in_msg.Sender; - if (TBEs[address].InitialRequestTime != zero_time() && in_msg.InitialRequestTime != zero_time()) { - assert(TBEs[address].InitialRequestTime == in_msg.InitialRequestTime); + assert(is_valid(tbe)); + DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs); + tbe.NumPendingMsgs := tbe.NumPendingMsgs - in_msg.Acks; + DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs); + tbe.LastResponder := in_msg.Sender; + if (tbe.InitialRequestTime != zero_time() && in_msg.InitialRequestTime != zero_time()) { + assert(tbe.InitialRequestTime == in_msg.InitialRequestTime); } if (in_msg.InitialRequestTime != zero_time()) { - TBEs[address].InitialRequestTime := in_msg.InitialRequestTime; + tbe.InitialRequestTime := in_msg.InitialRequestTime; } - if (TBEs[address].ForwardRequestTime != zero_time() && in_msg.ForwardRequestTime != zero_time()) { - assert(TBEs[address].ForwardRequestTime == in_msg.ForwardRequestTime); + if (tbe.ForwardRequestTime != zero_time() && in_msg.ForwardRequestTime != zero_time()) { + assert(tbe.ForwardRequestTime == in_msg.ForwardRequestTime); } if (in_msg.ForwardRequestTime != zero_time()) { - TBEs[address].ForwardRequestTime := in_msg.ForwardRequestTime; + tbe.ForwardRequestTime := in_msg.ForwardRequestTime; } - if (TBEs[address].FirstResponseTime == zero_time()) { - TBEs[address].FirstResponseTime := get_time(); + if (tbe.FirstResponseTime == zero_time()) { + tbe.FirstResponseTime := get_time(); } } } action(uo_updateCurrentOwner, "uo", desc="When moving SS state, update current owner.") { peek(responseToCache_in, ResponseMsg) { - TBEs[address].CurOwner := in_msg.Sender; + assert(is_valid(tbe)); + tbe.CurOwner := in_msg.Sender; } } @@ -747,10 +819,11 @@ machine(L1Cache, "AMD Hammer-like protocol") } action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") { - if (TBEs[address].NumPendingMsgs == 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; - if (TBEs[address].Sharers) { + if (tbe.Sharers) { out_msg.Type := TriggerType:ALL_ACKS; } else { out_msg.Type := TriggerType:ALL_ACKS_NO_SHARERS; @@ -760,23 +833,26 @@ machine(L1Cache, "AMD Hammer-like protocol") } action(p_decrementNumberOfMessagesByOne, "p", desc="Decrement the number of messages for which we're waiting by one") { - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - 1; + assert(is_valid(tbe)); + tbe.NumPendingMsgs := tbe.NumPendingMsgs - 1; } action(pp_incrementNumberOfMessagesByOne, "\p", desc="Increment the number of messages for which we're waiting by one") { - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs + 1; + assert(is_valid(tbe)); + tbe.NumPendingMsgs := tbe.NumPendingMsgs + 1; } action(q_sendDataFromTBEToCache, "q", desc="Send data from TBE to cache") { peek(forwardToCache_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.Requestor); DPRINTF(RubySlicc, "%s\n", out_msg.Destination); - out_msg.DataBlk := TBEs[address].DataBlk; - out_msg.Dirty := TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; if (in_msg.DirectedProbe) { out_msg.Acks := machineCount(MachineType:L1Cache); } else { @@ -792,13 +868,14 @@ machine(L1Cache, "AMD Hammer-like protocol") action(qm_sendDataFromTBEToCache, "qm", desc="Send data from TBE to cache, multiple sharers") { peek(forwardToCache_in, RequestMsg) { enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceResponseType:DATA; out_msg.Sender := machineID; out_msg.Destination := in_msg.MergedRequestors; DPRINTF(RubySlicc, "%s\n", out_msg.Destination); - out_msg.DataBlk := TBEs[address].DataBlk; - out_msg.Dirty := TBEs[address].Dirty; + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; out_msg.Acks := machineCount(MachineType:L1Cache); out_msg.MessageSize := MessageSizeType:Response_Data; out_msg.InitialRequestTime := in_msg.InitialRequestTime; @@ -809,48 +886,52 @@ machine(L1Cache, "AMD Hammer-like protocol") action(qq_sendDataFromTBEToMemory, "\q", desc="Send data from TBE to memory") { enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Sender := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.Dirty := TBEs[address].Dirty; - if (TBEs[address].Dirty) { + out_msg.Dirty := tbe.Dirty; + if (tbe.Dirty) { out_msg.Type := CoherenceResponseType:WB_DIRTY; - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Data; } else { out_msg.Type := CoherenceResponseType:WB_CLEAN; // NOTE: in a real system this would not send data. We send // data here only so we can check it at the memory - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Control; } } } action(r_setSharerBit, "r", desc="We saw other sharers") { - TBEs[address].Sharers := true; + assert(is_valid(tbe)); + tbe.Sharers := true; } action(s_deallocateTBE, "s", desc="Deallocate TBE") { TBEs.deallocate(address); + unset_tbe(); } action(t_sendExclusiveDataFromTBEToMemory, "t", desc="Send exclusive data from TBE to memory") { enqueue(unblockNetwork_out, ResponseMsg, latency=cache_response_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Sender := machineID; out_msg.Destination.add(map_Address_to_Directory(address)); - out_msg.DataBlk := TBEs[address].DataBlk; - out_msg.Dirty := TBEs[address].Dirty; - if (TBEs[address].Dirty) { + out_msg.DataBlk := tbe.DataBlk; + out_msg.Dirty := tbe.Dirty; + if (tbe.Dirty) { out_msg.Type := CoherenceResponseType:WB_EXCLUSIVE_DIRTY; - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Data; } else { out_msg.Type := CoherenceResponseType:WB_EXCLUSIVE_CLEAN; // NOTE: in a real system this would not send data. We send // data here only so we can check it at the memory - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; out_msg.MessageSize := MessageSizeType:Writeback_Control; } } @@ -858,18 +939,20 @@ machine(L1Cache, "AMD Hammer-like protocol") action(u_writeDataToCache, "u", desc="Write data to cache") { peek(responseToCache_in, ResponseMsg) { - getCacheEntry(address).DataBlk := in_msg.DataBlk; - getCacheEntry(address).Dirty := in_msg.Dirty; + assert(is_valid(cache_entry)); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty; } } action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") { peek(responseToCache_in, ResponseMsg) { + assert(is_valid(cache_entry)); DPRINTF(RubySlicc, "Cached Data Block: %s, Msg Data Block: %s\n", - getCacheEntry(address).DataBlk, in_msg.DataBlk); - assert(getCacheEntry(address).DataBlk == in_msg.DataBlk); - getCacheEntry(address).DataBlk := in_msg.DataBlk; - getCacheEntry(address).Dirty := in_msg.Dirty || getCacheEntry(address).Dirty; + cache_entry.DataBlk, in_msg.DataBlk); + assert(cache_entry.DataBlk == in_msg.DataBlk); + cache_entry.DataBlk := in_msg.DataBlk; + cache_entry.Dirty := in_msg.Dirty || cache_entry.Dirty; } } @@ -879,26 +962,28 @@ machine(L1Cache, "AMD Hammer-like protocol") } else { L1IcacheMemory.deallocate(address); } + unset_cache_entry(); } action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") { - if (L1DcacheMemory.isTagPresent(address) == false) { - L1DcacheMemory.allocate(address, new Entry); + if (is_invalid(cache_entry)) { + set_cache_entry(L1DcacheMemory.allocate(address, new Entry)); } } action(jj_allocateL1ICacheBlock, "\j", desc="Set L1 I-cache tag equal to tag of block B.") { - if (L1IcacheMemory.isTagPresent(address) == false) { - L1IcacheMemory.allocate(address, new Entry); + if (is_invalid(cache_entry)) { + set_cache_entry(L1IcacheMemory.allocate(address, new Entry)); } } action(vv_allocateL2CacheBlock, "\v", desc="Set L2 cache tag equal to tag of block B.") { - L2cacheMemory.allocate(address, new Entry); + set_cache_entry(L2cacheMemory.allocate(address, new Entry)); } action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") { L2cacheMemory.deallocate(address); + unset_cache_entry(); } action(uu_profileMiss, "\u", desc="Profile the demand miss") { @@ -1513,4 +1598,3 @@ machine(L1Cache, "AMD Hammer-like protocol") l_popForwardQueue; } } - diff --git a/src/mem/protocol/MOESI_hammer-dir.sm b/src/mem/protocol/MOESI_hammer-dir.sm index e6e474e95..8f9ce2360 100644 --- a/src/mem/protocol/MOESI_hammer-dir.sm +++ b/src/mem/protocol/MOESI_hammer-dir.sm @@ -166,6 +166,11 @@ machine(Directory, "AMD Hammer-like protocol") bool isPresent(Address); } + void set_cache_entry(AbstractCacheEntry b); + void unset_cache_entry(); + void set_tbe(TBE a); + void unset_tbe(); + // ** OBJECTS ** TBETable TBEs, template_hack="<Directory_TBE>"; @@ -174,17 +179,21 @@ machine(Directory, "AMD Hammer-like protocol") return static_cast(Entry, directory[addr]); } - PfEntry getPfEntry(Address addr), return_by_ref="yes" { - return static_cast(PfEntry, probeFilter[addr]); + PfEntry getProbeFilterEntry(Address addr), return_by_pointer="yes" { + if(probe_filter_enabled) { + PfEntry pfEntry := static_cast(PfEntry, "pointer", probeFilter.lookup(addr)); + return pfEntry; + } + return OOD; } - State getState(Address addr) { - if (TBEs.isPresent(addr)) { - return TBEs[addr].TBEState; + State getState(TBE tbe, PfEntry pf_entry, Address addr) { + if (is_valid(tbe)) { + return tbe.TBEState; } else { if (probe_filter_enabled) { - if (probeFilter.isTagPresent(addr)) { - assert(getPfEntry(addr).PfState == getDirectoryEntry(addr).DirectoryState); + if (is_valid(pf_entry)) { + assert(pf_entry.PfState == getDirectoryEntry(addr).DirectoryState); } else { assert(getDirectoryEntry(addr).DirectoryState == State:E); } @@ -193,21 +202,21 @@ machine(Directory, "AMD Hammer-like protocol") } } - void setState(Address addr, State state) { - if (TBEs.isPresent(addr)) { - TBEs[addr].TBEState := state; + void setState(TBE tbe, PfEntry pf_entry, Address addr, State state) { + if (is_valid(tbe)) { + tbe.TBEState := state; } if (probe_filter_enabled) { - if (probeFilter.isTagPresent(addr)) { - getPfEntry(addr).PfState := state; + if (is_valid(pf_entry)) { + pf_entry.PfState := state; } if (state == State:NX || state == State:NO || state == State:S || state == State:O) { - assert(probeFilter.isTagPresent(addr)); + assert(is_valid(pf_entry)); } } if (state == State:E || state == State:NX || state == State:NO || state == State:S || state == State:O) { - assert(TBEs.isPresent(addr) == false); + assert(is_valid(tbe) == false); } getDirectoryEntry(addr).DirectoryState := state; } @@ -242,14 +251,20 @@ machine(Directory, "AMD Hammer-like protocol") in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=5) { if (triggerQueue_in.isReady()) { peek(triggerQueue_in, TriggerMsg) { + PfEntry pf_entry := getProbeFilterEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == TriggerType:ALL_ACKS) { - trigger(Event:All_acks_and_owner_data, in_msg.Address); + trigger(Event:All_acks_and_owner_data, in_msg.Address, + pf_entry, tbe); } else if (in_msg.Type == TriggerType:ALL_ACKS_OWNER_EXISTS) { - trigger(Event:All_acks_and_shared_data, in_msg.Address); + trigger(Event:All_acks_and_shared_data, in_msg.Address, + pf_entry, tbe); } else if (in_msg.Type == TriggerType:ALL_ACKS_NO_SHARERS) { - trigger(Event:All_acks_and_data_no_sharers, in_msg.Address); + trigger(Event:All_acks_and_data_no_sharers, in_msg.Address, + pf_entry, tbe); } else if (in_msg.Type == TriggerType:ALL_UNBLOCKS) { - trigger(Event:All_Unblocks, in_msg.Address); + trigger(Event:All_Unblocks, in_msg.Address, + pf_entry, tbe); } else { error("Unexpected message"); } @@ -260,20 +275,24 @@ machine(Directory, "AMD Hammer-like protocol") in_port(unblockNetwork_in, ResponseMsg, unblockToDir, rank=4) { if (unblockNetwork_in.isReady()) { peek(unblockNetwork_in, ResponseMsg) { + PfEntry pf_entry := getProbeFilterEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == CoherenceResponseType:UNBLOCK) { - trigger(Event:Unblock, in_msg.Address); + trigger(Event:Unblock, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:UNBLOCKS) { - trigger(Event:UnblockS, in_msg.Address); + trigger(Event:UnblockS, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:UNBLOCKM) { - trigger(Event:UnblockM, in_msg.Address); + trigger(Event:UnblockM, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:WB_CLEAN) { - trigger(Event:Writeback_Clean, in_msg.Address); + trigger(Event:Writeback_Clean, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:WB_DIRTY) { - trigger(Event:Writeback_Dirty, in_msg.Address); + trigger(Event:Writeback_Dirty, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:WB_EXCLUSIVE_CLEAN) { - trigger(Event:Writeback_Exclusive_Clean, in_msg.Address); + trigger(Event:Writeback_Exclusive_Clean, in_msg.Address, + pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:WB_EXCLUSIVE_DIRTY) { - trigger(Event:Writeback_Exclusive_Dirty, in_msg.Address); + trigger(Event:Writeback_Exclusive_Dirty, in_msg.Address, + pf_entry, tbe); } else { error("Invalid message"); } @@ -285,16 +304,18 @@ machine(Directory, "AMD Hammer-like protocol") in_port(responseToDir_in, ResponseMsg, responseToDir, rank=3) { if (responseToDir_in.isReady()) { peek(responseToDir_in, ResponseMsg) { + PfEntry pf_entry := getProbeFilterEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == CoherenceResponseType:ACK) { - trigger(Event:Ack, in_msg.Address); + trigger(Event:Ack, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:ACK_SHARED) { - trigger(Event:Shared_Ack, in_msg.Address); + trigger(Event:Shared_Ack, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) { - trigger(Event:Shared_Data, in_msg.Address); + trigger(Event:Shared_Data, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA) { - trigger(Event:Data, in_msg.Address); + trigger(Event:Data, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == CoherenceResponseType:DATA_EXCLUSIVE) { - trigger(Event:Exclusive_Data, in_msg.Address); + trigger(Event:Exclusive_Data, in_msg.Address, pf_entry, tbe); } else { error("Unexpected message"); } @@ -306,10 +327,12 @@ machine(Directory, "AMD Hammer-like protocol") in_port(memQueue_in, MemoryMsg, memBuffer, rank=2) { if (memQueue_in.isReady()) { peek(memQueue_in, MemoryMsg) { + PfEntry pf_entry := getProbeFilterEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == MemoryRequestType:MEMORY_READ) { - trigger(Event:Memory_Data, in_msg.Address); + trigger(Event:Memory_Data, in_msg.Address, pf_entry, tbe); } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) { - trigger(Event:Memory_Ack, in_msg.Address); + trigger(Event:Memory_Ack, in_msg.Address, pf_entry, tbe); } else { DPRINTF(RubySlicc, "%d\n", in_msg.Type); error("Invalid message"); @@ -321,21 +344,29 @@ machine(Directory, "AMD Hammer-like protocol") in_port(requestQueue_in, RequestMsg, requestToDir, rank=1) { if (requestQueue_in.isReady()) { peek(requestQueue_in, RequestMsg) { + PfEntry pf_entry := getProbeFilterEntry(in_msg.Address); + TBE tbe := TBEs[in_msg.Address]; if (in_msg.Type == CoherenceRequestType:PUT) { - trigger(Event:PUT, in_msg.Address); + trigger(Event:PUT, in_msg.Address, pf_entry, tbe); } else { if (probe_filter_enabled) { - if (probeFilter.isTagPresent(in_msg.Address)) { - trigger(cache_request_to_event(in_msg.Type), in_msg.Address); + if (is_valid(pf_entry)) { + trigger(cache_request_to_event(in_msg.Type), in_msg.Address, + pf_entry, tbe); } else { if (probeFilter.cacheAvail(in_msg.Address)) { - trigger(cache_request_to_event(in_msg.Type), in_msg.Address); + trigger(cache_request_to_event(in_msg.Type), in_msg.Address, + pf_entry, tbe); } else { - trigger(Event:Pf_Replacement, probeFilter.cacheProbe(in_msg.Address)); + trigger(Event:Pf_Replacement, + probeFilter.cacheProbe(in_msg.Address), + getProbeFilterEntry(probeFilter.cacheProbe(in_msg.Address)), + TBEs[probeFilter.cacheProbe(in_msg.Address)]); } } } else { - trigger(cache_request_to_event(in_msg.Type), in_msg.Address); + trigger(cache_request_to_event(in_msg.Type), in_msg.Address, + pf_entry, tbe); } } } @@ -345,10 +376,12 @@ machine(Directory, "AMD Hammer-like protocol") in_port(dmaRequestQueue_in, DMARequestMsg, dmaRequestToDir, rank=0) { if (dmaRequestQueue_in.isReady()) { peek(dmaRequestQueue_in, DMARequestMsg) { + PfEntry pf_entry := getProbeFilterEntry(in_msg.LineAddress); + TBE tbe := TBEs[in_msg.LineAddress]; if (in_msg.Type == DMARequestType:READ) { - trigger(Event:DMA_READ, in_msg.LineAddress); + trigger(Event:DMA_READ, in_msg.LineAddress, pf_entry, tbe); } else if (in_msg.Type == DMARequestType:WRITE) { - trigger(Event:DMA_WRITE, in_msg.LineAddress); + trigger(Event:DMA_WRITE, in_msg.LineAddress, pf_entry, tbe); } else { error("Invalid message"); } @@ -360,25 +393,25 @@ machine(Directory, "AMD Hammer-like protocol") action(r_setMRU, "\rr", desc="manually set the MRU bit for pf entry" ) { if (probe_filter_enabled) { - assert(probeFilter.isTagPresent(address)); + assert(is_valid(cache_entry)); probeFilter.setMRU(address); } } action(auno_assertUnblockerNotOwner, "auno", desc="assert unblocker not owner") { if (probe_filter_enabled) { - assert(probeFilter.isTagPresent(address)); + assert(is_valid(cache_entry)); peek(unblockNetwork_in, ResponseMsg) { - assert(getPfEntry(address).Owner != in_msg.Sender); + assert(cache_entry.Owner != in_msg.Sender); } } } action(uo_updateOwnerIfPf, "uo", desc="update owner") { if (probe_filter_enabled) { - assert(probeFilter.isTagPresent(address)); + assert(is_valid(cache_entry)); peek(unblockNetwork_in, ResponseMsg) { - getPfEntry(address).Owner := in_msg.Sender; + cache_entry.Owner := in_msg.Sender; } } } @@ -410,8 +443,8 @@ machine(Directory, "AMD Hammer-like protocol") action(pfa_probeFilterAllocate, "pfa", desc="Allocate ProbeFilterEntry") { if (probe_filter_enabled) { peek(requestQueue_in, RequestMsg) { - probeFilter.allocate(address, new PfEntry); - getPfEntry(in_msg.Address).Owner := in_msg.Requestor; + set_cache_entry(probeFilter.allocate(address, new PfEntry)); + cache_entry.Owner := in_msg.Requestor; } } } @@ -419,92 +452,103 @@ machine(Directory, "AMD Hammer-like protocol") action(pfd_probeFilterDeallocate, "pfd", desc="Deallocate ProbeFilterEntry") { if (probe_filter_enabled) { probeFilter.deallocate(address); + unset_cache_entry(); } } action(ppfd_possibleProbeFilterDeallocate, "ppfd", desc="Deallocate ProbeFilterEntry") { - if (probe_filter_enabled && probeFilter.isTagPresent(address)) { + if (probe_filter_enabled && is_valid(cache_entry)) { probeFilter.deallocate(address); + unset_cache_entry(); } } action(v_allocateTBE, "v", desc="Allocate TBE") { peek(requestQueue_in, RequestMsg) { TBEs.allocate(address); - TBEs[address].PhysicalAddress := address; - TBEs[address].ResponseType := CoherenceResponseType:NULL; + set_tbe(TBEs[address]); + tbe.PhysicalAddress := address; + tbe.ResponseType := CoherenceResponseType:NULL; } } action(vd_allocateDmaRequestInTBE, "vd", desc="Record Data in TBE") { peek(dmaRequestQueue_in, DMARequestMsg) { TBEs.allocate(address); - TBEs[address].DmaDataBlk := in_msg.DataBlk; - TBEs[address].PhysicalAddress := in_msg.PhysicalAddress; - TBEs[address].Len := in_msg.Len; - TBEs[address].DmaRequestor := in_msg.Requestor; - TBEs[address].ResponseType := CoherenceResponseType:DATA_EXCLUSIVE; + set_tbe(TBEs[address]); + tbe.DmaDataBlk := in_msg.DataBlk; + tbe.PhysicalAddress := in_msg.PhysicalAddress; + tbe.Len := in_msg.Len; + tbe.DmaRequestor := in_msg.Requestor; + tbe.ResponseType := CoherenceResponseType:DATA_EXCLUSIVE; // // One ack for each last-level cache // - TBEs[address].NumPendingMsgs := machineCount(MachineType:L1Cache); + tbe.NumPendingMsgs := machineCount(MachineType:L1Cache); // // Assume initially that the caches store a clean copy and that memory // will provide the data // - TBEs[address].CacheDirty := false; + tbe.CacheDirty := false; } } action(pa_setPendingMsgsToAll, "pa", desc="set pending msgs to all") { - TBEs[address].NumPendingMsgs := machineCount(MachineType:L1Cache); + assert(is_valid(tbe)); + tbe.NumPendingMsgs := machineCount(MachineType:L1Cache); } action(po_setPendingMsgsToOne, "po", desc="set pending msgs to one") { - TBEs[address].NumPendingMsgs := 1; + assert(is_valid(tbe)); + tbe.NumPendingMsgs := 1; } action(w_deallocateTBE, "w", desc="Deallocate TBE") { TBEs.deallocate(address); + unset_tbe(); } action(sa_setAcksToOne, "sa", desc="Forwarded request, set the ack amount to one") { - TBEs[address].Acks := 1; + assert(is_valid(tbe)); + tbe.Acks := 1; } action(saa_setAcksToAllIfPF, "saa", desc="Non-forwarded request, set the ack amount to all") { + assert(is_valid(tbe)); if (probe_filter_enabled) { - TBEs[address].Acks := machineCount(MachineType:L1Cache); + tbe.Acks := machineCount(MachineType:L1Cache); } else { - TBEs[address].Acks := 1; + tbe.Acks := 1; } } action(m_decrementNumberOfMessages, "m", desc="Decrement the number of messages for which we're waiting") { peek(responseToDir_in, ResponseMsg) { + assert(is_valid(tbe)); assert(in_msg.Acks > 0); - DPRINTF(RubySlicc, "%d\n", TBEs[address].NumPendingMsgs); + DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs); // // Note that cache data responses will have an ack count of 2. However, // directory DMA requests must wait for acks from all LLC caches, so // only decrement by 1. // - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - 1; - DPRINTF(RubySlicc, "%d\n", TBEs[address].NumPendingMsgs); + tbe.NumPendingMsgs := tbe.NumPendingMsgs - 1; + DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs); } } action(mu_decrementNumberOfUnblocks, "mu", desc="Decrement the number of messages for which we're waiting") { peek(unblockNetwork_in, ResponseMsg) { + assert(is_valid(tbe)); assert(in_msg.Type == CoherenceResponseType:UNBLOCKS); - DPRINTF(RubySlicc, "%d\n", TBEs[address].NumPendingMsgs); + DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs); // // Note that cache data responses will have an ack count of 2. However, // directory DMA requests must wait for acks from all LLC caches, so // only decrement by 1. // - TBEs[address].NumPendingMsgs := TBEs[address].NumPendingMsgs - 1; - DPRINTF(RubySlicc, "%d\n", TBEs[address].NumPendingMsgs); + tbe.NumPendingMsgs := tbe.NumPendingMsgs - 1; + DPRINTF(RubySlicc, "%d\n", tbe.NumPendingMsgs); } } @@ -513,11 +557,12 @@ machine(Directory, "AMD Hammer-like protocol") } action(o_checkForCompletion, "o", desc="Check if we have received all the messages required for completion") { - if (TBEs[address].NumPendingMsgs == 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; - if (TBEs[address].Sharers) { - if (TBEs[address].Owned) { + if (tbe.Sharers) { + if (tbe.Owned) { out_msg.Type := TriggerType:ALL_ACKS_OWNER_EXISTS; } else { out_msg.Type := TriggerType:ALL_ACKS; @@ -530,7 +575,8 @@ machine(Directory, "AMD Hammer-like protocol") } action(os_checkForMergedGetSCompletion, "os", desc="Check for merged GETS completion") { - if (TBEs[address].NumPendingMsgs == 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs == 0) { enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; out_msg.Type := TriggerType:ALL_UNBLOCKS; @@ -539,17 +585,20 @@ machine(Directory, "AMD Hammer-like protocol") } action(sp_setPendingMsgsToMergedSharers, "sp", desc="Set pending messages to waiting sharers") { - TBEs[address].NumPendingMsgs := TBEs[address].GetSRequestors.count(); + assert(is_valid(tbe)); + tbe.NumPendingMsgs := tbe.GetSRequestors.count(); } action(spa_setPendingAcksToZeroIfPF, "spa", desc="if probe filter, no need to wait for acks") { if (probe_filter_enabled) { - TBEs[address].NumPendingMsgs := 0; + assert(is_valid(tbe)); + tbe.NumPendingMsgs := 0; } } action(sc_signalCompletionIfPF, "sc", desc="indicate that we should skip waiting for cpu acks") { - if (TBEs[address].NumPendingMsgs == 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs == 0) { assert(probe_filter_enabled); enqueue(triggerQueue_out, TriggerMsg) { out_msg.Address := address; @@ -561,14 +610,15 @@ machine(Directory, "AMD Hammer-like protocol") action(d_sendData, "d", desc="Send data to requestor") { peek(memQueue_in, MemoryMsg) { enqueue(responseNetwork_out, ResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.Address := address; - out_msg.Type := TBEs[address].ResponseType; + out_msg.Type := tbe.ResponseType; out_msg.Sender := machineID; out_msg.Destination.add(in_msg.OriginalRequestorMachId); out_msg.DataBlk := in_msg.DataBlk; DPRINTF(RubySlicc, "%s\n", out_msg.DataBlk); out_msg.Dirty := false; // By definition, the block is now clean - out_msg.Acks := TBEs[address].Acks; + out_msg.Acks := tbe.Acks; DPRINTF(RubySlicc, "%d\n", out_msg.Acks); assert(out_msg.Acks > 0); out_msg.MessageSize := MessageSizeType:Response_Data; @@ -579,6 +629,7 @@ machine(Directory, "AMD Hammer-like protocol") action(dr_sendDmaData, "dr", desc="Send Data to DMA controller from memory") { peek(memQueue_in, MemoryMsg) { enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:DATA; @@ -587,7 +638,7 @@ machine(Directory, "AMD Hammer-like protocol") // split it up if need be // out_msg.DataBlk := in_msg.DataBlk; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -596,6 +647,7 @@ machine(Directory, "AMD Hammer-like protocol") action(dt_sendDmaDataFromTbe, "dt", desc="Send Data to DMA controller from tbe") { peek(triggerQueue_in, TriggerMsg) { enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:DATA; @@ -603,8 +655,8 @@ machine(Directory, "AMD Hammer-like protocol") // we send the entire data block and rely on the dma controller to // split it up if need be // - out_msg.DataBlk := TBEs[address].DataBlk; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.DataBlk := tbe.DataBlk; + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Response_Data; } } @@ -612,39 +664,45 @@ machine(Directory, "AMD Hammer-like protocol") action(da_sendDmaAck, "da", desc="Send Ack to DMA controller") { enqueue(dmaResponseNetwork_out, DMAResponseMsg, latency="1") { + assert(is_valid(tbe)); out_msg.PhysicalAddress := address; out_msg.LineAddress := address; out_msg.Type := DMAResponseType:ACK; - out_msg.Destination.add(TBEs[address].DmaRequestor); + out_msg.Destination.add(tbe.DmaRequestor); out_msg.MessageSize := MessageSizeType:Writeback_Control; } } action(rx_recordExclusiveInTBE, "rx", desc="Record Exclusive in TBE") { peek(requestQueue_in, RequestMsg) { - TBEs[address].ResponseType := CoherenceResponseType:DATA_EXCLUSIVE; + assert(is_valid(tbe)); + tbe.ResponseType := CoherenceResponseType:DATA_EXCLUSIVE; } } action(r_recordDataInTBE, "rt", desc="Record Data in TBE") { peek(requestQueue_in, RequestMsg) { - TBEs[address].ResponseType := CoherenceResponseType:DATA; + assert(is_valid(tbe)); + tbe.ResponseType := CoherenceResponseType:DATA; } } action(rs_recordGetSRequestor, "rs", desc="Record GETS requestor in TBE") { peek(requestQueue_in, RequestMsg) { - TBEs[address].GetSRequestors.add(in_msg.Requestor); + assert(is_valid(tbe)); + tbe.GetSRequestors.add(in_msg.Requestor); } } action(r_setSharerBit, "r", desc="We saw other sharers") { - TBEs[address].Sharers := true; + assert(is_valid(tbe)); + tbe.Sharers := true; } action(so_setOwnerBit, "so", desc="We saw other sharers") { - TBEs[address].Sharers := true; - TBEs[address].Owned := true; + assert(is_valid(tbe)); + tbe.Sharers := true; + tbe.Owned := true; } action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") { @@ -676,7 +734,8 @@ machine(Directory, "AMD Hammer-like protocol") } action(fn_forwardRequestIfNecessary, "fn", desc="Forward requests if necessary") { - if ((machineCount(MachineType:L1Cache) > 1) && (TBEs[address].Acks <= 1)) { + assert(is_valid(tbe)); + if ((machineCount(MachineType:L1Cache) > 1) && (tbe.Acks <= 1)) { peek(requestQueue_in, RequestMsg) { enqueue(forwardNetwork_out, RequestMsg, latency=memory_controller_latency) { out_msg.Address := address; @@ -707,10 +766,11 @@ machine(Directory, "AMD Hammer-like protocol") action(io_invalidateOwnerRequest, "io", desc="invalidate all copies") { if (machineCount(MachineType:L1Cache) > 1) { enqueue(forwardNetwork_out, RequestMsg, latency=memory_controller_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:INV; out_msg.Requestor := machineID; - out_msg.Destination.add(getPfEntry(address).Owner); + out_msg.Destination.add(cache_entry.Owner); out_msg.MessageSize := MessageSizeType:Request_Control; out_msg.DirectedProbe := true; } @@ -742,9 +802,10 @@ machine(Directory, "AMD Hammer-like protocol") // peek(unblockNetwork_in, ResponseMsg) { enqueue(forwardNetwork_out, RequestMsg, latency=memory_controller_latency) { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := CoherenceRequestType:MERGED_GETS; - out_msg.MergedRequestors := TBEs[address].GetSRequestors; + out_msg.MergedRequestors := tbe.GetSRequestors; if (in_msg.Type == CoherenceResponseType:UNBLOCKS) { out_msg.Destination.add(in_msg.CurOwner); } else { @@ -762,10 +823,11 @@ machine(Directory, "AMD Hammer-like protocol") if (probe_filter_enabled) { peek(requestQueue_in, RequestMsg) { enqueue(forwardNetwork_out, RequestMsg, latency=memory_controller_latency) { + assert(is_valid(cache_entry)); out_msg.Address := address; out_msg.Type := in_msg.Type; out_msg.Requestor := in_msg.Requestor; - out_msg.Destination.add(getPfEntry(address).Owner); + out_msg.Destination.add(cache_entry.Owner); out_msg.MessageSize := MessageSizeType:Request_Control; out_msg.DirectedProbe := true; out_msg.InitialRequestTime := in_msg.InitialRequestTime; @@ -789,7 +851,8 @@ machine(Directory, "AMD Hammer-like protocol") } action(f_forwardWriteFromDma, "fw", desc="Forward requests") { - if (TBEs[address].NumPendingMsgs > 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs > 0) { peek(dmaRequestQueue_in, DMARequestMsg) { enqueue(forwardNetwork_out, RequestMsg, latency=memory_controller_latency) { out_msg.Address := address; @@ -807,7 +870,8 @@ machine(Directory, "AMD Hammer-like protocol") } action(f_forwardReadFromDma, "fr", desc="Forward requests") { - if (TBEs[address].NumPendingMsgs > 0) { + assert(is_valid(tbe)); + if (tbe.NumPendingMsgs > 0) { peek(dmaRequestQueue_in, DMARequestMsg) { enqueue(forwardNetwork_out, RequestMsg, latency=memory_controller_latency) { out_msg.Address := address; @@ -860,16 +924,18 @@ machine(Directory, "AMD Hammer-like protocol") action(r_recordMemoryData, "rd", desc="record data from memory to TBE") { peek(memQueue_in, MemoryMsg) { - if (TBEs[address].CacheDirty == false) { - TBEs[address].DataBlk := in_msg.DataBlk; + assert(is_valid(tbe)); + if (tbe.CacheDirty == false) { + tbe.DataBlk := in_msg.DataBlk; } } } action(r_recordCacheData, "rc", desc="record data from cache response to TBE") { peek(responseToDir_in, ResponseMsg) { - TBEs[address].CacheDirty := true; - TBEs[address].DataBlk := in_msg.DataBlk; + assert(is_valid(tbe)); + tbe.CacheDirty := true; + tbe.DataBlk := in_msg.DataBlk; } } @@ -893,26 +959,30 @@ machine(Directory, "AMD Hammer-like protocol") action(dwt_writeDmaDataFromTBE, "dwt", desc="DMA Write data to memory from TBE") { DPRINTF(RubySlicc, "%s\n", getDirectoryEntry(address).DataBlk); - getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk; + assert(is_valid(tbe)); + getDirectoryEntry(address).DataBlk := tbe.DataBlk; DPRINTF(RubySlicc, "%s\n", getDirectoryEntry(address).DataBlk); - getDirectoryEntry(address).DataBlk.copyPartial(TBEs[address].DmaDataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + getDirectoryEntry(address).DataBlk.copyPartial(tbe.DmaDataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); DPRINTF(RubySlicc, "%s\n", getDirectoryEntry(address).DataBlk); } action(wdt_writeDataFromTBE, "wdt", desc="DMA Write data to memory from TBE") { + assert(is_valid(tbe)); DPRINTF(RubySlicc, "%s\n", getDirectoryEntry(address).DataBlk); - getDirectoryEntry(address).DataBlk := TBEs[address].DataBlk; + getDirectoryEntry(address).DataBlk := tbe.DataBlk; DPRINTF(RubySlicc, "%s\n", getDirectoryEntry(address).DataBlk); } action(a_assertCacheData, "ac", desc="Assert that a cache provided the data") { - assert(TBEs[address].CacheDirty); + assert(is_valid(tbe)); + assert(tbe.CacheDirty); } action(ano_assertNotOwner, "ano", desc="Assert that request is not current owner") { if (probe_filter_enabled) { peek(requestQueue_in, RequestMsg) { - assert(getPfEntry(address).Owner != in_msg.Requestor); + assert(is_valid(cache_entry)); + assert(cache_entry.Owner != in_msg.Requestor); } } } @@ -929,12 +999,13 @@ machine(Directory, "AMD Hammer-like protocol") action(ld_queueMemoryDmaWrite, "ld", desc="Write DMA data to memory") { enqueue(memQueue_out, MemoryMsg, latency="1") { + assert(is_valid(tbe)); out_msg.Address := address; out_msg.Type := MemoryRequestType:MEMORY_WB; // first, initialize the data blk to the current version of system memory - out_msg.DataBlk := TBEs[address].DataBlk; + out_msg.DataBlk := tbe.DataBlk; // then add the dma write data - out_msg.DataBlk.copyPartial(TBEs[address].DmaDataBlk, addressOffset(TBEs[address].PhysicalAddress), TBEs[address].Len); + out_msg.DataBlk.copyPartial(tbe.DmaDataBlk, addressOffset(tbe.PhysicalAddress), tbe.Len); DPRINTF(RubySlicc, "%s\n", out_msg); } } diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm index 9d3cd6634..1d68768e4 100644 --- a/src/mem/protocol/RubySlicc_Types.sm +++ b/src/mem/protocol/RubySlicc_Types.sm @@ -117,15 +117,16 @@ external_type(DirectoryMemory) { void invalidateBlock(Address); } -external_type(AbstractCacheEntry, primitive="yes"); +external_type(AbstractCacheEntry, primitive="yes") { + void changePermission(AccessPermission); +} external_type(CacheMemory) { bool cacheAvail(Address); Address cacheProbe(Address); - void allocate(Address, AbstractCacheEntry); + AbstractCacheEntry allocate(Address, AbstractCacheEntry); void deallocate(Address); AbstractCacheEntry lookup(Address); - void changePermission(Address, AccessPermission); bool isTagPresent(Address); void profileMiss(CacheMsg); diff --git a/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc b/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc index 3d8972c40..c0fe6ffd3 100644 --- a/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc +++ b/src/mem/ruby/slicc_interface/AbstractCacheEntry.cc @@ -32,9 +32,26 @@ AbstractCacheEntry::AbstractCacheEntry() { m_Address.setAddress(0); m_Permission = AccessPermission_NotPresent; + m_locked = -1; } AbstractCacheEntry::~AbstractCacheEntry() { } +AccessPermission +AbstractCacheEntry::getPermission() const +{ + return m_Permission; +} + +void +AbstractCacheEntry::changePermission(AccessPermission new_perm) +{ + m_Permission = new_perm; + if ((new_perm == AccessPermission_Invalid) || + (new_perm == AccessPermission_NotPresent) || + (new_perm == AccessPermission_Stale)) { + m_locked = -1; + } +} diff --git a/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh b/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh index 66cce58a1..87c96a9cb 100644 --- a/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh +++ b/src/mem/ruby/slicc_interface/AbstractCacheEntry.hh @@ -48,11 +48,17 @@ class AbstractCacheEntry : public AbstractEntry AbstractCacheEntry(); virtual ~AbstractCacheEntry() = 0; + // Get/Set permission of cache entry + AccessPermission getPermission() const; + void changePermission(AccessPermission new_perm); + Address m_Address; // Address of this block, required by CacheMemory Time m_LastRef; // Last time this block was referenced, required // by CacheMemory AccessPermission m_Permission; // Access permission for this // block, required by CacheMemory + int m_locked; // Holds info whether the address is locked, + // required for implementing LL/SC }; inline std::ostream& @@ -64,4 +70,3 @@ operator<<(std::ostream& out, const AbstractCacheEntry& obj) } #endif // __MEM_RUBY_SLICC_INTERFACE_ABSTRACTCACHEENTRY_HH__ - diff --git a/src/mem/ruby/system/CacheMemory.cc b/src/mem/ruby/system/CacheMemory.cc index e9d0d8851..b80c1c356 100644 --- a/src/mem/ruby/system/CacheMemory.cc +++ b/src/mem/ruby/system/CacheMemory.cc @@ -75,13 +75,10 @@ CacheMemory::init() assert(false); m_cache.resize(m_cache_num_sets); - m_locked.resize(m_cache_num_sets); for (int i = 0; i < m_cache_num_sets; i++) { m_cache[i].resize(m_cache_assoc); - m_locked[i].resize(m_cache_assoc); for (int j = 0; j < m_cache_assoc; j++) { m_cache[i][j] = NULL; - m_locked[i][j] = -1; } } } @@ -255,7 +252,7 @@ CacheMemory::cacheAvail(const Address& address) const return false; } -void +AbstractCacheEntry* CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) { assert(address == line_address(address)); @@ -273,13 +270,13 @@ CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry) set[i]->m_Permission = AccessPermission_Invalid; DPRINTF(RubyCache, "Allocate clearing lock for addr: %x\n", address); - m_locked[cacheSet][i] = -1; + set[i]->m_locked = -1; m_tag_index[address] = i; m_replacementPolicy_ptr-> touch(cacheSet, i, g_eventQueue_ptr->getTime()); - return; + return entry; } } panic("Allocate didn't find an available entry"); @@ -296,9 +293,6 @@ CacheMemory::deallocate(const Address& address) if (loc != -1) { delete m_cache[cacheSet][loc]; m_cache[cacheSet][loc] = NULL; - DPRINTF(RubyCache, "Deallocate clearing lock for addr: %x\n", - address); - m_locked[cacheSet][loc] = -1; m_tag_index.erase(address); } } @@ -316,49 +310,25 @@ CacheMemory::cacheProbe(const Address& address) const } // looks an address up in the cache -AbstractCacheEntry& +AbstractCacheEntry* CacheMemory::lookup(const Address& address) { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); - assert(loc != -1); - return *m_cache[cacheSet][loc]; + if(loc == -1) return NULL; + return m_cache[cacheSet][loc]; } // looks an address up in the cache -const AbstractCacheEntry& +const AbstractCacheEntry* CacheMemory::lookup(const Address& address) const { assert(address == line_address(address)); Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); - assert(loc != -1); - return *m_cache[cacheSet][loc]; -} - -AccessPermission -CacheMemory::getPermission(const Address& address) const -{ - assert(address == line_address(address)); - return lookup(address).m_Permission; -} - -void -CacheMemory::changePermission(const Address& address, - AccessPermission new_perm) -{ - assert(address == line_address(address)); - lookup(address).m_Permission = new_perm; - Index cacheSet = addressToCacheSet(address); - int loc = findTagInSet(cacheSet, address); - if ((new_perm == AccessPermission_Invalid) || - (new_perm == AccessPermission_NotPresent) || - (new_perm == AccessPermission_Stale)) { - DPRINTF(RubyCache, "Permission clearing lock for addr: %x\n", address); - m_locked[cacheSet][loc] = -1; - } - assert(getPermission(address) == new_perm); + if(loc == -1) return NULL; + return m_cache[cacheSet][loc]; } // Sets the most recently used bit for a cache block @@ -460,10 +430,10 @@ void CacheMemory::getMemoryValue(const Address& addr, char* value, unsigned size_in_bytes) { - AbstractCacheEntry& entry = lookup(line_address(addr)); + AbstractCacheEntry* entry = lookup(line_address(addr)); unsigned startByte = addr.getAddress() - line_address(addr).getAddress(); for (unsigned i = 0; i < size_in_bytes; ++i) { - value[i] = entry.getDataBlk().getByte(i + startByte); + value[i] = entry->getDataBlk().getByte(i + startByte); } } @@ -471,11 +441,11 @@ void CacheMemory::setMemoryValue(const Address& addr, char* value, unsigned size_in_bytes) { - AbstractCacheEntry& entry = lookup(line_address(addr)); + AbstractCacheEntry* entry = lookup(line_address(addr)); unsigned startByte = addr.getAddress() - line_address(addr).getAddress(); assert(size_in_bytes > 0); for (unsigned i = 0; i < size_in_bytes; ++i) { - entry.getDataBlk().setByte(i + startByte, value[i]); + entry->getDataBlk().setByte(i + startByte, value[i]); } // entry = lookup(line_address(addr)); @@ -489,7 +459,7 @@ CacheMemory::setLocked(const Address& address, int context) Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); assert(loc != -1); - m_locked[cacheSet][loc] = context; + m_cache[cacheSet][loc]->m_locked = context; } void @@ -500,7 +470,7 @@ CacheMemory::clearLocked(const Address& address) Index cacheSet = addressToCacheSet(address); int loc = findTagInSet(cacheSet, address); assert(loc != -1); - m_locked[cacheSet][loc] = -1; + m_cache[cacheSet][loc]->m_locked = -1; } bool @@ -511,7 +481,7 @@ CacheMemory::isLocked(const Address& address, int context) int loc = findTagInSet(cacheSet, address); assert(loc != -1); DPRINTF(RubyCache, "Testing Lock for addr: %llx cur %d con %d\n", - address, m_locked[cacheSet][loc], context); - return m_locked[cacheSet][loc] == context; + address, m_cache[cacheSet][loc]->m_locked, context); + return m_cache[cacheSet][loc]->m_locked == context; } diff --git a/src/mem/ruby/system/CacheMemory.hh b/src/mem/ruby/system/CacheMemory.hh index 3ef951821..1f0ffd500 100644 --- a/src/mem/ruby/system/CacheMemory.hh +++ b/src/mem/ruby/system/CacheMemory.hh @@ -82,7 +82,7 @@ class CacheMemory : public SimObject bool cacheAvail(const Address& address) const; // find an unused entry and sets the tag appropriate for the address - void allocate(const Address& address, AbstractCacheEntry* new_entry); + AbstractCacheEntry* allocate(const Address& address, AbstractCacheEntry* new_entry); // Explicitly free up this address void deallocate(const Address& address); @@ -91,12 +91,8 @@ class CacheMemory : public SimObject Address cacheProbe(const Address& address) const; // looks an address up in the cache - AbstractCacheEntry& lookup(const Address& address); - const AbstractCacheEntry& lookup(const Address& address) const; - - // Get/Set permission of cache block - AccessPermission getPermission(const Address& address) const; - void changePermission(const Address& address, AccessPermission new_perm); + AbstractCacheEntry* lookup(const Address& address); + const AbstractCacheEntry* lookup(const Address& address) const; int getLatency() const { return m_latency; } @@ -158,7 +154,6 @@ class CacheMemory : public SimObject // The second index is the the amount associativity. m5::hash_map<Address, int> m_tag_index; std::vector<std::vector<AbstractCacheEntry*> > m_cache; - std::vector<std::vector<int> > m_locked; AbstractReplacementPolicy *m_replacementPolicy_ptr; diff --git a/src/mem/ruby/system/TBETable.hh b/src/mem/ruby/system/TBETable.hh index da33cc9d2..022654bce 100644 --- a/src/mem/ruby/system/TBETable.hh +++ b/src/mem/ruby/system/TBETable.hh @@ -61,8 +61,7 @@ class TBETable return (m_number_of_TBEs - m_map.size()) >= n; } - ENTRY& lookup(const Address& address); - const ENTRY& lookup(const Address& address) const; + ENTRY* lookup(const Address& address); // Print cache contents void print(std::ostream& out) const; @@ -117,21 +116,13 @@ TBETable<ENTRY>::deallocate(const Address& address) // looks an address up in the cache template<class ENTRY> -inline ENTRY& +inline ENTRY* TBETable<ENTRY>::lookup(const Address& address) { - assert(isPresent(address)); - return m_map.find(address)->second; + if(m_map.find(address) != m_map.end()) return &(m_map.find(address)->second); + return NULL; } -// looks an address up in the cache -template<class ENTRY> -inline const ENTRY& -TBETable<ENTRY>::lookup(const Address& address) const -{ - assert(isPresent(address)); - return m_map.find(address)->second; -} template<class ENTRY> inline void diff --git a/src/mem/slicc/ast/ActionDeclAST.py b/src/mem/slicc/ast/ActionDeclAST.py index e85aa25b8..2a8fb0639 100644 --- a/src/mem/slicc/ast/ActionDeclAST.py +++ b/src/mem/slicc/ast/ActionDeclAST.py @@ -39,6 +39,11 @@ class ActionDeclAST(DeclAST): def generate(self): resources = {} + + machine = self.symtab.state_machine + if machine is None: + self.error("Action declaration not part of a machine.") + if self.statement_list: # Add new local vars self.symtab.pushFrame() @@ -52,6 +57,16 @@ class ActionDeclAST(DeclAST): "addr", self.pairs) self.symtab.newSymbol(var) + if machine.TBEType != None: + var = Var(self.symtab, "tbe", self.location, machine.TBEType, + "(*m_tbe_ptr)", self.pairs) + self.symtab.newSymbol(var) + + if machine.EntryType != None: + var = Var(self.symtab, "cache_entry", self.location, + machine.EntryType, "(*m_cache_entry_ptr)", self.pairs) + self.symtab.newSymbol(var) + # Do not allows returns in actions code = self.slicc.codeFormatter() self.statement_list.generate(code, None) @@ -61,10 +76,6 @@ class ActionDeclAST(DeclAST): self.symtab.popFrame() - machine = self.symtab.state_machine - if machine is None: - self.error("Action declaration not part of a machine.") - action = Action(self.symtab, self.ident, resources, self.location, self.pairs) machine.addAction(action) diff --git a/src/mem/slicc/ast/FormalParamAST.py b/src/mem/slicc/ast/FormalParamAST.py index c64731196..142e837cc 100644 --- a/src/mem/slicc/ast/FormalParamAST.py +++ b/src/mem/slicc/ast/FormalParamAST.py @@ -48,7 +48,17 @@ class FormalParamAST(AST): param = "param_%s" % self.ident # Add to symbol table - v = Var(self.symtab, self.ident, self.location, type, param, - self.pairs) - self.symtab.newSymbol(v) + if self.pointer or str(type) == "TBE" or ( + "interface" in type and type["interface"] == "AbstractCacheEntry"): + + v = Var(self.symtab, self.ident, self.location, type, + "(*%s)" % param, self.pairs) + self.symtab.newSymbol(v) + return type, "%s* %s" % (type.c_ident, param) + + else: + v = Var(self.symtab, self.ident, self.location, type, param, + self.pairs) + self.symtab.newSymbol(v) + return type, "%s %s" % (type.c_ident, param) diff --git a/src/mem/slicc/ast/FuncCallExprAST.py b/src/mem/slicc/ast/FuncCallExprAST.py index 829203d53..2c5e9ea4d 100644 --- a/src/mem/slicc/ast/FuncCallExprAST.py +++ b/src/mem/slicc/ast/FuncCallExprAST.py @@ -89,6 +89,7 @@ class FuncCallExprAST(ExprAST): len(func.param_types), len(self.exprs)) cvec = [] + type_vec = [] for expr,expected_type in zip(self.exprs, func.param_types): # Check the types of the parameter actual_type,param_code = expr.inline(True) @@ -96,6 +97,7 @@ class FuncCallExprAST(ExprAST): expr.error("Type mismatch: expected: %s actual: %s" % \ (expected_type, actual_type)) cvec.append(param_code) + type_vec.append(expected_type) # OK, the semantics of "trigger" here is that, ports in the # machine have different priorities. We always check the first @@ -115,8 +117,25 @@ class FuncCallExprAST(ExprAST): code(''' { Address addr = ${{cvec[1]}}; - TransitionResult result = doTransition(${{cvec[0]}}, ${machine}_getState(addr), addr); +''') + if machine.TBEType != None and machine.EntryType != None: + code(''' + TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, ${{cvec[3]}}, addr); +''') + elif machine.TBEType != None: + code(''' + TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr); +''') + elif machine.EntryType != None: + code(''' + TransitionResult result = doTransition(${{cvec[0]}}, ${{cvec[2]}}, addr); +''') + else: + code(''' + TransitionResult result = doTransition(${{cvec[0]}}, addr); +''') + code(''' if (result == TransitionResult_Valid) { counter++; continue; // Check the first port again @@ -175,6 +194,16 @@ if (!(${{cvec[0]}})) { elif self.proc_name == "continueProcessing": code("counter++;") code("continue; // Check the first port again") + + elif self.proc_name == "set_cache_entry": + code("set_cache_entry(m_cache_entry_ptr, %s);" %(cvec[0])); + elif self.proc_name == "unset_cache_entry": + code("unset_cache_entry(m_cache_entry_ptr);"); + elif self.proc_name == "set_tbe": + code("set_tbe(m_tbe_ptr, %s);" %(cvec[0])); + elif self.proc_name == "unset_tbe": + code("unset_tbe(m_tbe_ptr);"); + else: # Normal function @@ -184,7 +213,27 @@ if (!(${{cvec[0]}})) { if "external" not in func and not func.isInternalMachineFunc: internal = "m_chip_ptr->" - params = ', '.join(str(c) for c in cvec) + params = "" + first_param = True + + for (param_code, type) in zip(cvec, type_vec): + if str(type) == "TBE" or ("interface" in type and + type["interface"] == "AbstractCacheEntry"): + + if first_param: + params = str(param_code).replace('*','') + first_param = False + else: + params += ', ' + params += str(param_code).replace('*',''); + else: + if first_param: + params = str(param_code) + first_param = False + else: + params += ', ' + params += str(param_code); + fix = code.nofix() code('(${internal}${{func.c_ident}}($params))') code.fix(fix) diff --git a/src/mem/slicc/ast/IfStatementAST.py b/src/mem/slicc/ast/IfStatementAST.py index 359173203..0e023195c 100644 --- a/src/mem/slicc/ast/IfStatementAST.py +++ b/src/mem/slicc/ast/IfStatementAST.py @@ -55,13 +55,17 @@ class IfStatementAST(StatementAST): code('if ($cond_code) {') # Then part code.indent() + self.symtab.pushFrame() self.then.generate(code, return_type) + self.symtab.popFrame() code.dedent() # Else part if self.else_: code('} else {') code.indent() + self.symtab.pushFrame() self.else_.generate(code, return_type) + self.symtab.popFrame() code.dedent() code('}') # End scope diff --git a/src/mem/slicc/ast/InPortDeclAST.py b/src/mem/slicc/ast/InPortDeclAST.py index 5aa27bae8..c6fadb9e7 100644 --- a/src/mem/slicc/ast/InPortDeclAST.py +++ b/src/mem/slicc/ast/InPortDeclAST.py @@ -51,6 +51,10 @@ class InPortDeclAST(DeclAST): symtab = self.symtab void_type = symtab.find("void", Type) + machine = symtab.state_machine + if machine is None: + self.error("InPort declaration not part of a machine.") + code = self.slicc.codeFormatter() queue_type = self.var_expr.generate(code) if not queue_type.isInPort: @@ -79,6 +83,11 @@ class InPortDeclAST(DeclAST): param_types.append(type) + if machine.EntryType != None: + param_types.append(machine.EntryType) + if machine.TBEType != None: + param_types.append(machine.TBEType) + # Add the trigger method - FIXME, this is a bit dirty pairs = { "external" : "yes" } func = Func(self.symtab, "trigger", self.location, void_type, @@ -123,13 +132,10 @@ class InPortDeclAST(DeclAST): rcode.indent() self.statements.generate(rcode, None) in_port["c_code_in_port"] = str(rcode) + symtab.popFrame() # Add port to state machine - machine = symtab.state_machine - if machine is None: - self.error("InPort declaration not part of a machine.") - machine.addInPort(in_port) # Include max_rank to be used by StateMachine.py diff --git a/src/mem/slicc/ast/IsValidPtrExprAST.py b/src/mem/slicc/ast/IsValidPtrExprAST.py new file mode 100644 index 000000000..850f45e96 --- /dev/null +++ b/src/mem/slicc/ast/IsValidPtrExprAST.py @@ -0,0 +1,53 @@ +# +# Copyright (c) 2011 Mark D. Hill and David A. Wood +# 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. +# + +from slicc.ast.ExprAST import ExprAST +from slicc.symbols import Type + +class IsValidPtrExprAST(ExprAST): + def __init__(self, slicc, variable, flag): + super(IsValidPtrExprAST, self).__init__(slicc) + self.variable = variable + self.flag = flag + + def __repr__(self): + return "[IsValidPtrExprAST: %r]" % self.variable + + def generate(self, code): + # Make sure the variable is valid + fix = code.nofix() + code("(") + var_type, var_code = self.variable.inline(True); + var_code_str = str(var_code).replace('*','') + if self.flag: + code("${var_code_str} != NULL)") + else: + code("${var_code_str} == NULL)") + code.fix(fix) + type = self.symtab.find("bool", Type) + return type diff --git a/src/mem/slicc/ast/LocalVariableAST.py b/src/mem/slicc/ast/LocalVariableAST.py new file mode 100644 index 000000000..82e73ba7a --- /dev/null +++ b/src/mem/slicc/ast/LocalVariableAST.py @@ -0,0 +1,54 @@ +# +# Copyright (c) 2011 Mark D. Hill and David A. Wood +# 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. +# + +from slicc.ast.StatementAST import StatementAST +from slicc.symbols import Var + +class LocalVariableAST(StatementAST): + def __init__(self, slicc, type_ast, ident): + super(LocalVariableAST, self).__init__(slicc) + self.type_ast = type_ast + self.ident = ident + + def __repr__(self): + return "[LocalVariableAST: %r %r]" % (self.type_ast, self.ident) + + @property + def name(self): + return self.var_name + + def generate(self, code): + type = self.type_ast.type; + ident = "%s" % self.ident; + + # Add to symbol table + v = Var(self.symtab, self.ident, self.location, type, ident, + self.pairs) + self.symtab.newSymbol(v) + code += "%s* %s" % (type.c_ident, ident) + return type diff --git a/src/mem/slicc/ast/MethodCallExprAST.py b/src/mem/slicc/ast/MethodCallExprAST.py index 84009c076..6a2977533 100644 --- a/src/mem/slicc/ast/MethodCallExprAST.py +++ b/src/mem/slicc/ast/MethodCallExprAST.py @@ -97,48 +97,67 @@ class MemberMethodCallExprAST(MethodCallExprAST): prefix = "" implements_interface = False - if methodId not in obj_type.methods: - # - # The initial method check has failed, but before generating an - # error we must check whether any of the paramTypes implement - # an interface. If so, we must check if the method ids using - # the inherited types exist. - # - # This code is a temporary fix and only checks for the methodId - # where all paramTypes are converted to their inherited type. The - # right way to do this is to replace slicc's simple string - # comparison for determining the correct overloaded method, with a - # more robust param by param check. + + if methodId in obj_type.methods: + return_type = obj_type.methods[methodId].return_type + + else: # - implemented_paramTypes = [] - for paramType in paramTypes: - implemented_paramType = paramType - if paramType.isInterface: - implements_interface = True - implemented_paramType.abstract_ident = paramType["interface"] + # Check whether the method is implemented by the super class + if "interface" in obj_type: + interface_type = self.symtab.find(obj_type["interface"]); + + if methodId in interface_type.methods: + return_type = interface_type.methods[methodId].return_type + obj_type = interface_type + else: - implemented_paramType.abstract_ident = paramType.c_ident - - implemented_paramTypes.append(implemented_paramType) + self.error("Invalid method call: " \ + "Type '%s' does not have a method %s, '%s'", + obj_type, self.proc_name, methodId) - if implements_interface: - implementedMethodId = obj_type.methodIdAbstract(self.proc_name, - implemented_paramTypes) else: - implementedMethodId = "" - - if implementedMethodId not in obj_type.methods: - self.error("Invalid method call: " \ - "Type '%s' does not have a method '%s' nor '%s'", - obj_type, methodId, implementedMethodId) - else: - # - # Replace the methodId with the implementedMethodId found in - # the method list. - # - methodId = implementedMethodId - - return_type = obj_type.methods[methodId].return_type + # + # The initial method check has failed, but before generating an + # error we must check whether any of the paramTypes implement + # an interface. If so, we must check if the method ids using + # the inherited types exist. + # + # This code is a temporary fix and only checks for the methodId + # where all paramTypes are converted to their inherited type. The + # right way to do this is to replace slicc's simple string + # comparison for determining the correct overloaded method, with a + # more robust param by param check. + # + implemented_paramTypes = [] + for paramType in paramTypes: + implemented_paramType = paramType + if paramType.isInterface: + implements_interface = True + implemented_paramType.abstract_ident = paramType["interface"] + else: + implemented_paramType.abstract_ident = paramType.c_ident + + implemented_paramTypes.append(implemented_paramType) + + if implements_interface: + implementedMethodId = obj_type.methodIdAbstract(self.proc_name, + implemented_paramTypes) + else: + implementedMethodId = "" + + if implementedMethodId not in obj_type.methods: + self.error("Invalid method call: " \ + "Type '%s' does not have a method %s, '%s' nor '%s'", + obj_type, self.proc_name, methodId, implementedMethodId) + else: + # + # Replace the methodId with the implementedMethodId found in + # the method list. + # + methodId = implementedMethodId + return_type = obj_type.methods[methodId].return_type + if return_type.isInterface: prefix = "static_cast<%s &>" % return_type.c_ident prefix = "%s((%s)." % (prefix, code) diff --git a/src/mem/slicc/ast/OodAST.py b/src/mem/slicc/ast/OodAST.py new file mode 100644 index 000000000..0f4cf141c --- /dev/null +++ b/src/mem/slicc/ast/OodAST.py @@ -0,0 +1,40 @@ +# +# Copyright (c) 2011 Mark D. Hill and David A. Wood +# 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. +# + +from slicc.ast.ExprAST import ExprAST + +class OodAST(ExprAST): + def __init__(self, slicc): + super(OodAST, self).__init__(slicc) + + def __repr__(self): + return "[Ood:]" + + def generate(self, code): + code += "NULL" + return "OOD" diff --git a/src/mem/slicc/ast/ReturnStatementAST.py b/src/mem/slicc/ast/ReturnStatementAST.py index f1aff1c32..754bb4c9f 100644 --- a/src/mem/slicc/ast/ReturnStatementAST.py +++ b/src/mem/slicc/ast/ReturnStatementAST.py @@ -45,7 +45,7 @@ class ReturnStatementAST(StatementAST): self.error("Invalid 'return' statement") # The return type must match - if return_type != actual_type: + if actual_type != "OOD" and return_type != actual_type: self.expr_ast.error("Return type miss-match, expected return " + "type is '%s', actual is '%s'", return_type, actual_type) diff --git a/src/mem/slicc/ast/StaticCastAST.py b/src/mem/slicc/ast/StaticCastAST.py index 3a48f398e..71280ba67 100644 --- a/src/mem/slicc/ast/StaticCastAST.py +++ b/src/mem/slicc/ast/StaticCastAST.py @@ -27,18 +27,22 @@ from slicc.ast.ExprAST import ExprAST class StaticCastAST(ExprAST): - def __init__(self, slicc, type_ast, expr_ast): + def __init__(self, slicc, type_ast, type_modifier, expr_ast): super(StaticCastAST, self).__init__(slicc) self.type_ast = type_ast self.expr_ast = expr_ast + self.type_modifier = type_modifier def __repr__(self): return "[StaticCastAST: %r]" % self.expr_ast def generate(self, code): actual_type, ecode = self.expr_ast.inline(True) - code('static_cast<${{self.type_ast.type.c_ident}} &>($ecode)') + if self.type_modifier == "pointer": + code('static_cast<${{self.type_ast.type.c_ident}} *>($ecode)') + else: + code('static_cast<${{self.type_ast.type.c_ident}} &>($ecode)') if not "interface" in self.type_ast.type: self.expr_ast.error("static cast only premitted for those types " \ diff --git a/src/mem/slicc/ast/TypeDeclAST.py b/src/mem/slicc/ast/TypeDeclAST.py index ecdb5949b..983e86882 100644 --- a/src/mem/slicc/ast/TypeDeclAST.py +++ b/src/mem/slicc/ast/TypeDeclAST.py @@ -50,10 +50,15 @@ class TypeDeclAST(DeclAST): def generate(self): ident = str(self.type_ast) + machine = self.symtab.state_machine # Make the new type new_type = Type(self.symtab, ident, self.location, self.pairs, self.state_machine) + + if machine: + machine.addType(new_type) + self.symtab.newSymbol(new_type) # Add all of the fields of the type to it diff --git a/src/mem/slicc/ast/__init__.py b/src/mem/slicc/ast/__init__.py index b854612be..ae797ecd3 100644 --- a/src/mem/slicc/ast/__init__.py +++ b/src/mem/slicc/ast/__init__.py @@ -46,11 +46,14 @@ from slicc.ast.FuncDeclAST import * from slicc.ast.IfStatementAST import * from slicc.ast.InPortDeclAST import * from slicc.ast.InfixOperatorExprAST import * +from slicc.ast.IsValidPtrExprAST import * from slicc.ast.LiteralExprAST import * +from slicc.ast.LocalVariableAST import * from slicc.ast.MachineAST import * from slicc.ast.MemberExprAST import * from slicc.ast.MethodCallExprAST import * from slicc.ast.NewExprAST import * +from slicc.ast.OodAST import * from slicc.ast.ObjDeclAST import * from slicc.ast.OutPortDeclAST import * from slicc.ast.PairAST import * diff --git a/src/mem/slicc/parser.py b/src/mem/slicc/parser.py index ce665465f..bb958f746 100644 --- a/src/mem/slicc/parser.py +++ b/src/mem/slicc/parser.py @@ -165,12 +165,15 @@ class SLICC(Grammar): 'check_stop_slots' : 'CHECK_STOP_SLOTS', 'static_cast' : 'STATIC_CAST', 'if' : 'IF', + 'is_valid' : 'IS_VALID', + 'is_invalid' : 'IS_INVALID', 'else' : 'ELSE', 'return' : 'RETURN', 'THIS' : 'THIS', 'CHIP' : 'CHIP', 'void' : 'VOID', 'new' : 'NEW', + 'OOD' : 'OOD', } literals = ':[]{}(),=' @@ -576,7 +579,11 @@ class SLICC(Grammar): def p_statement__static_cast(self, p): "aexpr : STATIC_CAST '(' type ',' expr ')'" - p[0] = ast.StaticCastAST(self, p[3], p[5]) + p[0] = ast.StaticCastAST(self, p[3], "ref", p[5]) + + def p_statement__static_cast_ptr(self, p): + "aexpr : STATIC_CAST '(' type ',' STRING ',' expr ')'" + p[0] = ast.StaticCastAST(self, p[3], p[5], p[7]) def p_statement__return(self, p): "statement : RETURN expr SEMI" @@ -603,6 +610,10 @@ class SLICC(Grammar): "aexpr : var" p[0] = p[1] + def p_expr__localvar(self, p): + "aexpr : type ident" + p[0] = ast.LocalVariableAST(self, p[1], p[2]) + def p_expr__literal(self, p): "aexpr : literal" p[0] = p[1] @@ -619,6 +630,10 @@ class SLICC(Grammar): "aexpr : NEW type" p[0] = ast.NewExprAST(self, p[2]) + def p_expr__null(self, p): + "aexpr : OOD" + p[0] = ast.OodAST(self) + # globally access a local chip component and call a method def p_expr__local_chip_method(self, p): "aexpr : THIS DOT var '[' expr ']' DOT var DOT ident '(' exprs ')'" @@ -687,6 +702,14 @@ class SLICC(Grammar): "aexpr : '(' expr ')'" p[0] = p[2] + def p_expr__is_valid_ptr(self, p): + "aexpr : IS_VALID '(' var ')'" + p[0] = ast.IsValidPtrExprAST(self, p[3], True) + + def p_expr__is_invalid_ptr(self, p): + "aexpr : IS_INVALID '(' var ')'" + p[0] = ast.IsValidPtrExprAST(self, p[3], False) + def p_literal__string(self, p): "literal : STRING" p[0] = ast.LiteralExprAST(self, p[1], "std::string") diff --git a/src/mem/slicc/symbols/Func.py b/src/mem/slicc/symbols/Func.py index a5751344a..e1670e3ed 100644 --- a/src/mem/slicc/symbols/Func.py +++ b/src/mem/slicc/symbols/Func.py @@ -60,6 +60,8 @@ class Func(Symbol): void_type = self.symtab.find("void", Type) if "return_by_ref" in self and self.return_type != void_type: return_type += "&" + elif "return_by_pointer" in self and self.return_type != void_type: + return_type += "*" return "%s %s(%s);" % (return_type, self.c_ident, ", ".join(self.param_strings)) @@ -87,6 +89,8 @@ class Func(Symbol): return_type = self.return_type.c_ident if "return_by_ref" in self and self.return_type != void_type: return_type += "&" + if "return_by_pointer" in self and self.return_type != void_type: + return_type += "*" if self.isInternalMachineFunc: klass = "%s_Controller" % self.machineStr diff --git a/src/mem/slicc/symbols/StateMachine.py b/src/mem/slicc/symbols/StateMachine.py index 145284726..b0d663c43 100644 --- a/src/mem/slicc/symbols/StateMachine.py +++ b/src/mem/slicc/symbols/StateMachine.py @@ -46,6 +46,7 @@ class StateMachine(Symbol): super(StateMachine, self).__init__(symtab, ident, location, pairs) self.table = None self.config_parameters = config_parameters + for param in config_parameters: if param.pointer: var = Var(symtab, param.name, location, param.type_ast.type, @@ -62,6 +63,8 @@ class StateMachine(Symbol): self.in_ports = [] self.functions = [] self.objects = [] + self.TBEType = None + self.EntryType = None self.message_buffer_names = [] @@ -107,6 +110,21 @@ class StateMachine(Symbol): def addObject(self, obj): self.objects.append(obj) + def addType(self, type): + type_ident = '%s' % type.c_ident + + if type_ident == "%s_TBE" %self.ident: + if self.TBEType != None: + self.error("Multiple Transaction Buffer types in a " \ + "single machine."); + self.TBEType = type + + elif "interface" in type and "AbstractCacheEntry" == type["interface"]: + if self.EntryType != None: + self.error("Multiple AbstractCacheEntry types in a " \ + "single machine."); + self.EntryType = type + # Needs to be called before accessing the table def buildTable(self): assert self.table is None @@ -264,12 +282,35 @@ private: int m_number_of_TBEs; TransitionResult doTransition(${ident}_Event event, - ${ident}_State state, +''') + + if self.EntryType != None: + code(''' + ${{self.EntryType.c_ident}}* m_cache_entry_ptr, +''') + if self.TBEType != None: + code(''' + ${{self.TBEType.c_ident}}* m_tbe_ptr, +''') + + code(''' const Address& addr); TransitionResult doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, +''') + + if self.TBEType != None: + code(''' + ${{self.TBEType.c_ident}}*& m_tbe_ptr, +''') + if self.EntryType != None: + code(''' + ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, +''') + + code(''' const Address& addr); std::string m_name; @@ -299,13 +340,42 @@ static int m_num_controllers; if proto: code('$proto') + if self.EntryType != None: + code(''' + +// Set and Reset for cache_entry variable +void set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry); +void unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr); +''') + + if self.TBEType != None: + code(''' + +// Set and Reset for tbe variable +void set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${ident}_TBE* m_new_tbe); +void unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr); +''') + code(''' // Actions ''') - for action in self.actions.itervalues(): - code('/** \\brief ${{action.desc}} */') - code('void ${{action.ident}}(const Address& addr);') + if self.TBEType != None and self.EntryType != None: + for action in self.actions.itervalues(): + code('/** \\brief ${{action.desc}} */') + code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') + elif self.TBEType != None: + for action in self.actions.itervalues(): + code('/** \\brief ${{action.desc}} */') + code('void ${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr);') + elif self.EntryType != None: + for action in self.actions.itervalues(): + code('/** \\brief ${{action.desc}} */') + code('void ${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr);') + else: + for action in self.actions.itervalues(): + code('/** \\brief ${{action.desc}} */') + code('void ${{action.ident}}(const Address& addr);') # the controller internal variables code(''' @@ -731,15 +801,97 @@ void $c_ident::clearStats() { code(''' m_profiler.clearStats(); } +''') + + if self.EntryType != None: + code(''' + +// Set and Reset for cache_entry variable +void +$c_ident::set_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, AbstractCacheEntry* m_new_cache_entry) +{ + m_cache_entry_ptr = (${{self.EntryType.c_ident}}*)m_new_cache_entry; +} + +void +$c_ident::unset_cache_entry(${{self.EntryType.c_ident}}*& m_cache_entry_ptr) +{ + m_cache_entry_ptr = 0; +} +''') + + if self.TBEType != None: + code(''' + +// Set and Reset for tbe variable +void +$c_ident::set_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.TBEType.c_ident}}* m_new_tbe) +{ + m_tbe_ptr = m_new_tbe; +} + +void +$c_ident::unset_tbe(${{self.TBEType.c_ident}}*& m_tbe_ptr) +{ + m_tbe_ptr = NULL; +} +''') + + code(''' // Actions ''') + if self.TBEType != None and self.EntryType != None: + for action in self.actions.itervalues(): + if "c_code" not in action: + continue - for action in self.actions.itervalues(): - if "c_code" not in action: - continue + code(''' +/** \\brief ${{action.desc}} */ +void +$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) +{ + DPRINTF(RubyGenerated, "executing\\n"); + ${{action["c_code"]}} +} - code(''' +''') + elif self.TBEType != None: + for action in self.actions.itervalues(): + if "c_code" not in action: + continue + + code(''' +/** \\brief ${{action.desc}} */ +void +$c_ident::${{action.ident}}(${{self.TBEType.c_ident}}*& m_tbe_ptr, const Address& addr) +{ + DPRINTF(RubyGenerated, "executing\\n"); + ${{action["c_code"]}} +} + +''') + elif self.EntryType != None: + for action in self.actions.itervalues(): + if "c_code" not in action: + continue + + code(''' +/** \\brief ${{action.desc}} */ +void +$c_ident::${{action.ident}}(${{self.EntryType.c_ident}}*& m_cache_entry_ptr, const Address& addr) +{ + DPRINTF(RubyGenerated, "executing\\n"); + ${{action["c_code"]}} +} + +''') + else: + for action in self.actions.itervalues(): + if "c_code" not in action: + continue + + code(''' /** \\brief ${{action.desc}} */ void $c_ident::${{action.ident}}(const Address& addr) @@ -777,9 +929,6 @@ using namespace std; void ${ident}_Controller::wakeup() { - // DEBUG_EXPR(GENERATED_COMP, MedPrio, *this); - // DEBUG_EXPR(GENERATED_COMP, MedPrio, g_eventQueue_ptr->getTime()); - int counter = 0; while (true) { // Some cases will put us into an infinite loop without this limit @@ -850,9 +999,29 @@ ${ident}_Controller::wakeup() TransitionResult ${ident}_Controller::doTransition(${ident}_Event event, - ${ident}_State state, +''') + if self.EntryType != None: + code(''' + ${{self.EntryType.c_ident}}* m_cache_entry_ptr, +''') + if self.TBEType != None: + code(''' + ${{self.TBEType.c_ident}}* m_tbe_ptr, +''') + code(''' const Address &addr) { +''') + if self.TBEType != None and self.EntryType != None: + code('${ident}_State state = ${ident}_getState(m_tbe_ptr, m_cache_entry_ptr, addr);') + elif self.TBEType != None: + code('${ident}_State state = ${ident}_getState(m_tbe_ptr, addr);') + elif self.EntryType != None: + code('${ident}_State state = ${ident}_getState(m_cache_entry_ptr, addr);') + else: + code('${ident}_State state = ${ident}_getState(addr);') + + code(''' ${ident}_State next_state = state; DPRINTF(RubyGenerated, "%s, Time: %lld, state: %s, event: %s, addr: %s\\n", @@ -863,8 +1032,17 @@ ${ident}_Controller::doTransition(${ident}_Event event, addr); TransitionResult result = - doTransitionWorker(event, state, next_state, addr); +''') + if self.TBEType != None and self.EntryType != None: + code('doTransitionWorker(event, state, next_state, m_tbe_ptr, m_cache_entry_ptr, addr);') + elif self.TBEType != None: + code('doTransitionWorker(event, state, next_state, m_tbe_ptr, addr);') + elif self.EntryType != None: + code('doTransitionWorker(event, state, next_state, m_cache_entry_ptr, addr);') + else: + code('doTransitionWorker(event, state, next_state, addr);') + code(''' if (result == TransitionResult_Valid) { DPRINTF(RubyGenerated, "next_state: %s\\n", ${ident}_State_to_string(next_state)); @@ -877,7 +1055,17 @@ ${ident}_Controller::doTransition(${ident}_Event event, addr, GET_TRANSITION_COMMENT()); CLEAR_TRANSITION_COMMENT(); - ${ident}_setState(addr, next_state); +''') + if self.TBEType != None and self.EntryType != None: + code('${ident}_setState(m_tbe_ptr, m_cache_entry_ptr, addr, next_state);') + elif self.TBEType != None: + code('${ident}_setState(m_tbe_ptr, addr, next_state);') + elif self.EntryType != None: + code('${ident}_setState(m_cache_entry_ptr, addr, next_state);') + else: + code('${ident}_setState(addr, next_state);') + + code(''' } else if (result == TransitionResult_ResourceStall) { DPRINTFR(ProtocolTrace, "%7s %3s %10s%20s %6s>%-6s %s %s\\n", g_eventQueue_ptr->getTime(), m_version, "${ident}", @@ -902,6 +1090,17 @@ TransitionResult ${ident}_Controller::doTransitionWorker(${ident}_Event event, ${ident}_State state, ${ident}_State& next_state, +''') + + if self.TBEType != None: + code(''' + ${{self.TBEType.c_ident}}*& m_tbe_ptr, +''') + if self.EntryType != None: + code(''' + ${{self.EntryType.c_ident}}*& m_cache_entry_ptr, +''') + code(''' const Address& addr) { switch(HASH_FUN(state, event)) { @@ -950,8 +1149,18 @@ if (!%s.areNSlotsAvailable(%s)) if stall: case('return TransitionResult_ProtocolStall;') else: - for action in actions: - case('${{action.ident}}(addr);') + if self.TBEType != None and self.EntryType != None: + for action in actions: + case('${{action.ident}}(m_tbe_ptr, m_cache_entry_ptr, addr);') + elif self.TBEType != None: + for action in actions: + case('${{action.ident}}(m_tbe_ptr, addr);') + elif self.EntryType != None: + for action in actions: + case('${{action.ident}}(m_cache_entry_ptr, addr);') + else: + for action in actions: + case('${{action.ident}}(addr);') case('return TransitionResult_Valid;') case = str(case) |