+/*
+ * Copyright (c) 2009-2012 Mark D. Hill and David A. Wood
+ * Copyright (c) 2010-2012 Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
machine(L1Cache, "MI Example L1 Cache")
-: Sequencer * sequencer,
- CacheMemory * cacheMemory,
- int cache_response_latency = 12,
- int issue_latency = 2
+ : Sequencer * sequencer;
+ CacheMemory * cacheMemory;
+ Cycles cache_response_latency := 12;
+ Cycles issue_latency := 2;
+ bool send_evictions;
+
+ // NETWORK BUFFERS
+ MessageBuffer * requestFromCache, network="To", virtual_network="2",
+ ordered="true", vnet_type="request";
+ MessageBuffer * responseFromCache, network="To", virtual_network="4",
+ ordered="true", vnet_type="response";
+
+ MessageBuffer * forwardToCache, network="From", virtual_network="3",
+ ordered="true", vnet_type="forward";
+ MessageBuffer * responseToCache, network="From", virtual_network="4",
+ ordered="true", vnet_type="response";
{
-
- // NETWORK BUFFERS
- MessageBuffer requestFromCache, network="To", virtual_network="2", ordered="true";
- MessageBuffer responseFromCache, network="To", virtual_network="4", ordered="true";
-
- MessageBuffer forwardToCache, network="From", virtual_network="3", ordered="true";
- MessageBuffer responseToCache, network="From", virtual_network="4", ordered="true";
-
// STATES
- enumeration(State, desc="Cache states") {
- I, desc="Not Present/Invalid";
- II, desc="Not Present/Invalid, issued PUT";
- M, desc="Modified";
- MI, desc="Modified, issued PUT";
- MII, desc="Modified, issued PUTX, received nack";
+ state_declaration(State, desc="Cache states") {
+ I, AccessPermission:Invalid, desc="Not Present/Invalid";
+ II, AccessPermission:Busy, desc="Not Present/Invalid, issued PUT";
+ M, AccessPermission:Read_Write, desc="Modified";
+ MI, AccessPermission:Busy, desc="Modified, issued PUT";
+ MII, AccessPermission:Busy, desc="Modified, issued PUTX, received nack";
- IS, desc="Issued request for LOAD/IFETCH";
- IM, desc="Issued request for STORE/ATOMIC";
+ IS, AccessPermission:Busy, desc="Issued request for LOAD/IFETCH";
+ IM, AccessPermission:Busy, desc="Issued request for STORE/ATOMIC";
}
// EVENTS
DataBlock DataBlk, desc="Data in the block";
}
-
// TBE fields
structure(TBE, desc="...") {
State TBEState, desc="Transient state";
DataBlock DataBlk, desc="data for the block, required for concurrent writebacks";
}
- external_type(TBETable) {
+ structure(TBETable, external="yes") {
TBE lookup(Address);
void allocate(Address);
void deallocate(Address);
// STRUCTURES
+ TBETable TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs";
- 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();
+ void profileMsgDelay(int virtualNetworkType, Cycles b);
+ 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) {
- if (type == CacheRequestType:LD) {
+ Event mandatory_request_type_to_event(RubyRequestType type) {
+ if (type == RubyRequestType:LD) {
return Event:Load;
- } else if (type == CacheRequestType:IFETCH) {
+ } else if (type == RubyRequestType:IFETCH) {
return Event:Ifetch;
- } else if ((type == CacheRequestType:ST) || (type == CacheRequestType:ATOMIC)) {
+ } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) {
return Event:Store;
} else {
- error("Invalid CacheRequestType");
+ error("Invalid RubyRequestType");
}
}
- 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 (state == State:M) {
- cacheMemory.changePermission(addr, AccessPermission:Read_Write);
- } else {
- cacheMemory.changePermission(addr, AccessPermission:Invalid);
- }
+ if (is_valid(cache_entry)) {
+ cache_entry.CacheState := state;
}
}
+ AccessPermission getAccessPermission(Address addr) {
+ TBE tbe := TBEs[addr];
+ if(is_valid(tbe)) {
+ return L1Cache_State_to_permission(tbe.TBEState);
+ }
+
+ Entry cache_entry := getCacheEntry(addr);
+ if(is_valid(cache_entry)) {
+ return L1Cache_State_to_permission(cache_entry.CacheState);
+ }
+
+ return AccessPermission:NotPresent;
+ }
+
+ void setAccessPermission(Entry cache_entry, Address addr, State state) {
+ if (is_valid(cache_entry)) {
+ cache_entry.changePermission(L1Cache_State_to_permission(state));
+ }
+ }
+
+ DataBlock getDataBlock(Address addr), return_by_ref="yes" {
+ TBE tbe := TBEs[addr];
+ if(is_valid(tbe)) {
+ return tbe.DataBlk;
+ }
+
+ return getCacheEntry(addr).DataBlk;
+ }
// NETWORK PORTS
in_port(forwardRequestNetwork_in, RequestMsg, forwardToCache) {
if (forwardRequestNetwork_in.isReady()) {
- peek(forwardRequestNetwork_in, RequestMsg, block_on="Address") {
+ peek(forwardRequestNetwork_in, RequestMsg, block_on="Addr") {
+
+ Entry cache_entry := getCacheEntry(in_msg.Addr);
+ TBE tbe := TBEs[in_msg.Addr];
+
if (in_msg.Type == CoherenceRequestType:GETX) {
- trigger(Event:Fwd_GETX, in_msg.Address);
+ trigger(Event:Fwd_GETX, in_msg.Addr, cache_entry, tbe);
}
else if (in_msg.Type == CoherenceRequestType:WB_ACK) {
- trigger(Event:Writeback_Ack, in_msg.Address);
+ trigger(Event:Writeback_Ack, in_msg.Addr, cache_entry, tbe);
}
else if (in_msg.Type == CoherenceRequestType:WB_NACK) {
- trigger(Event:Writeback_Nack, in_msg.Address);
+ trigger(Event:Writeback_Nack, in_msg.Addr, cache_entry, tbe);
}
else if (in_msg.Type == CoherenceRequestType:INV) {
- trigger(Event:Inv, in_msg.Address);
+ trigger(Event:Inv, in_msg.Addr, cache_entry, tbe);
}
else {
error("Unexpected message");
in_port(responseNetwork_in, ResponseMsg, responseToCache) {
if (responseNetwork_in.isReady()) {
- peek(responseNetwork_in, ResponseMsg, block_on="Address") {
+ peek(responseNetwork_in, ResponseMsg, block_on="Addr") {
+
+ Entry cache_entry := getCacheEntry(in_msg.Addr);
+ TBE tbe := TBEs[in_msg.Addr];
+
if (in_msg.Type == CoherenceResponseType:DATA) {
- trigger(Event:Data, in_msg.Address);
+ trigger(Event:Data, in_msg.Addr, cache_entry, tbe);
}
else {
error("Unexpected message");
}
// Mandatory Queue
- in_port(mandatoryQueue_in, CacheMsg, mandatoryQueue, desc="...") {
+ in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...") {
if (mandatoryQueue_in.isReady()) {
- peek(mandatoryQueue_in, CacheMsg, block_on="LineAddress") {
-
+ peek(mandatoryQueue_in, RubyRequest, 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]);
}
}
}
// ACTIONS
action(a_issueRequest, "a", desc="Issue a request") {
- enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
- out_msg.Address := address;
+ enqueue(requestNetwork_out, RequestMsg, issue_latency) {
+ out_msg.Addr := address;
out_msg.Type := CoherenceRequestType:GETX;
out_msg.Requestor := machineID;
out_msg.Destination.add(map_Address_to_Directory(address));
}
action(b_issuePUT, "b", desc="Issue a PUT request") {
- enqueue(requestNetwork_out, RequestMsg, latency=issue_latency) {
- out_msg.Address := address;
+ enqueue(requestNetwork_out, RequestMsg, issue_latency) {
+ assert(is_valid(cache_entry));
+ out_msg.Addr := 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;
}
}
-
action(e_sendData, "e", desc="Send data from cache to requestor") {
peek(forwardRequestNetwork_in, RequestMsg) {
- enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
- out_msg.Address := address;
+ enqueue(responseNetwork_out, ResponseMsg, cache_response_latency) {
+ assert(is_valid(cache_entry));
+ out_msg.Addr := 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;
}
}
action(ee_sendDataFromTBE, "\e", desc="Send data from TBE to requestor") {
peek(forwardRequestNetwork_in, RequestMsg) {
- enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
- out_msg.Address := address;
+ enqueue(responseNetwork_out, ResponseMsg, cache_response_latency) {
+ assert(is_valid(tbe));
+ out_msg.Addr := 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();
}
}
}
action(n_popResponseQueue, "n", desc="Pop the response queue") {
- profileMsgDelay(1, responseNetwork_in.dequeue_getDelayCycles());
+ profileMsgDelay(1, responseNetwork_in.dequeue());
}
action(o_popForwardedRequestQueue, "o", desc="Pop the forwarded request queue") {
- profileMsgDelay(2, forwardRequestNetwork_in.dequeue_getDelayCycles());
+ profileMsgDelay(2, forwardRequestNetwork_in.dequeue());
}
- action(p_profileMiss, "p", desc="Profile cache miss") {
- peek(mandatoryQueue_in, CacheMsg) {
- cacheMemory.profileMiss(in_msg);
- }
+ action(p_profileMiss, "pi", desc="Profile cache miss") {
+ ++cacheMemory.demand_misses;
+ }
+
+ action(p_profileHit, "ph", desc="Profile cache miss") {
+ ++cacheMemory.demand_hits;
}
action(r_load_hit, "r", desc="Notify sequencer the load completed.") {
- DEBUG_EXPR(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, false);
+ }
+
+ action(rx_load_hit, "rx", desc="External load completed.") {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(is_valid(cache_entry));
+ DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+ sequencer.readCallback(address, cache_entry.DataBlk, true,
+ machineIDToMachineType(in_msg.Sender));
+ }
}
action(s_store_hit, "s", desc="Notify sequencer that store completed.") {
- DEBUG_EXPR(getCacheEntry(address).DataBlk);
- sequencer.writeCallback(address, getCacheEntry(address).DataBlk);
+ assert(is_valid(cache_entry));
+ DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+ sequencer.writeCallback(address, cache_entry.DataBlk, false);
}
+ action(sx_store_hit, "sx", desc="External store completed.") {
+ peek(responseNetwork_in, ResponseMsg) {
+ assert(is_valid(cache_entry));
+ DPRINTF(RubySlicc,"%s\n", cache_entry.DataBlk);
+ sequencer.writeCallback(address, cache_entry.DataBlk, true,
+ machineIDToMachineType(in_msg.Sender));
+ }
+ }
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(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
+ if (send_evictions) {
+ DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
+ sequencer.evictionCallback(address);
+ }
+ }
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") {
// TRANSITIONS
- transition({IS, IM, MI, II}, {Load, Ifetch, Store, Replacement}) {
+ transition({IS, IM, MI, II, MII}, {Load, Ifetch, Store, Replacement}) {
z_stall;
}
transition(M, Store) {
s_store_hit;
+ p_profileHit;
m_popMandatoryQueue;
}
transition(M, {Load, Ifetch}) {
r_load_hit;
+ p_profileHit;
m_popMandatoryQueue;
}
transition(IS, Data, M) {
u_writeDataToCache;
- r_load_hit;
+ rx_load_hit;
w_deallocateTBE;
n_popResponseQueue;
}
transition(IM, Data, M) {
u_writeDataToCache;
- s_store_hit;
+ sx_store_hit;
w_deallocateTBE;
n_popResponseQueue;
}
transition(M, Fwd_GETX, I) {
e_sendData;
+ forward_eviction_to_cpu;
o_popForwardedRequestQueue;
}
v_allocateTBE;
b_issuePUT;
x_copyDataFromCacheToTBE;
+ forward_eviction_to_cpu;
h_deallocateL1CacheBlock;
}
o_popForwardedRequestQueue;
}
}
-