MESI_Two_Level-L2cache.sm (14184:11ac1337c5e2) MESI_Two_Level-L2cache.sm (14300:22183ae13998)
1/*
2 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29machine(MachineType:L2Cache, "MESI Directory L2 Cache CMP")
30 : CacheMemory * L2cache;
31 Cycles l2_request_latency := 2;
32 Cycles l2_response_latency := 2;
33 Cycles to_l1_latency := 1;
34
35 // Message Queues
36 // From local bank of L2 cache TO the network
37 MessageBuffer * DirRequestFromL2Cache, network="To", virtual_network="0",
38 vnet_type="request"; // this L2 bank -> Memory
39
40 MessageBuffer * L1RequestFromL2Cache, network="To", virtual_network="2",
41 vnet_type="request"; // this L2 bank -> a local L1
42
43 MessageBuffer * responseFromL2Cache, network="To", virtual_network="1",
44 vnet_type="response"; // this L2 bank -> a local L1 || Memory
45
46 // FROM the network to this local bank of L2 cache
47 MessageBuffer * unblockToL2Cache, network="From", virtual_network="2",
48 vnet_type="unblock"; // a local L1 || Memory -> this L2 bank
49
50 MessageBuffer * L1RequestToL2Cache, network="From", virtual_network="0",
51 vnet_type="request"; // a local L1 -> this L2 bank
52
53 MessageBuffer * responseToL2Cache, network="From", virtual_network="1",
54 vnet_type="response"; // a local L1 || Memory -> this L2 bank
55{
56 // STATES
57 state_declaration(State, desc="L2 Cache states", default="L2Cache_State_NP") {
58 // Base states
59 NP, AccessPermission:Invalid, desc="Not present in either cache";
60 SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s";
61 M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b";
62 MT, AccessPermission:Maybe_Stale, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
63
64 // L2 replacement
65 M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
66 MT_I, AccessPermission:Busy, desc="L2 cache replacing, getting data from exclusive";
67 MCT_I, AccessPermission:Busy, desc="L2 cache replacing, clean in L2, getting data or ack from exclusive";
68 I_I, AccessPermission:Busy, desc="L2 replacing clean data, need to inv sharers and then drop data";
69 S_I, AccessPermission:Busy, desc="L2 replacing dirty data, collecting acks from L1s";
70
71 // Transient States for fetching data from memory
72 ISS, AccessPermission:Busy, desc="L2 idle, got single L1_GETS, issued memory fetch, have not seen response yet";
73 IS, AccessPermission:Busy, desc="L2 idle, got L1_GET_INSTR or multiple L1_GETS, issued memory fetch, have not seen response yet";
74 IM, AccessPermission:Busy, desc="L2 idle, got L1_GETX, issued memory fetch, have not seen response(s) yet";
75
76 // Blocking states
77 SS_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from SS";
78 MT_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from MT";
79
80 MT_IIB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, waiting for unblock and data";
81 MT_IB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got unblock, waiting for data";
82 MT_SB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got data, waiting for unblock";
83
84 }
85
86 // EVENTS
87 enumeration(Event, desc="L2 Cache events") {
88 // L2 events
89
90 // events initiated by the local L1s
91 L1_GET_INSTR, desc="a L1I GET INSTR request for a block maped to us";
92 L1_GETS, desc="a L1D GETS request for a block maped to us";
93 L1_GETX, desc="a L1D GETX request for a block maped to us";
94 L1_UPGRADE, desc="a L1D GETX request for a block maped to us";
95
96 L1_PUTX, desc="L1 replacing data";
97 L1_PUTX_old, desc="L1 replacing data, but no longer sharer";
98
99 // events initiated by this L2
100 L2_Replacement, desc="L2 Replacement", format="!r";
101 L2_Replacement_clean, desc="L2 Replacement, but data is clean", format="!r";
102
103 // events from memory controller
104 Mem_Data, desc="data from memory", format="!r";
105 Mem_Ack, desc="ack from memory", format="!r";
106
107 // M->S data writeback
108 WB_Data, desc="data from L1";
109 WB_Data_clean, desc="clean data from L1";
110 Ack, desc="writeback ack";
111 Ack_all, desc="writeback ack";
112
113 Unblock, desc="Unblock from L1 requestor";
114 Exclusive_Unblock, desc="Unblock from L1 requestor";
115
116 MEM_Inv, desc="Invalidation from directory";
117 }
118
119 // TYPES
120
121 // CacheEntry
122 structure(Entry, desc="...", interface="AbstractCacheEntry") {
123 State CacheState, desc="cache state";
124 NetDest Sharers, desc="tracks the L1 shares on-chip";
125 MachineID Exclusive, desc="Exclusive holder of block";
126 DataBlock DataBlk, desc="data for the block";
127 bool Dirty, default="false", desc="data is dirty";
128 }
129
130 // TBE fields
131 structure(TBE, desc="...") {
132 Addr addr, desc="Physical address for this TBE";
133 State TBEState, desc="Transient state";
134 DataBlock DataBlk, desc="Buffer for the data block";
135 bool Dirty, default="false", desc="Data is Dirty";
136
137 NetDest L1_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
138 MachineID L1_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
139 int pendingAcks, desc="number of pending acks for invalidates during writeback";
140 }
141
142 structure(TBETable, external="yes") {
143 TBE lookup(Addr);
144 void allocate(Addr);
145 void deallocate(Addr);
146 bool isPresent(Addr);
147 }
148
149 TBETable TBEs, template="<L2Cache_TBE>", constructor="m_number_of_TBEs";
150
151 Tick clockEdge();
152 Tick cyclesToTicks(Cycles c);
153 Cycles ticksToCycles(Tick t);
154
155 void set_cache_entry(AbstractCacheEntry a);
156 void unset_cache_entry();
157 void set_tbe(TBE a);
158 void unset_tbe();
159 void wakeUpBuffers(Addr a);
160 void profileMsgDelay(int virtualNetworkType, Cycles c);
161 MachineID mapAddressToMachine(Addr addr, MachineType mtype);
162
163 // inclusive cache, returns L2 entries only
164 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
165 return static_cast(Entry, "pointer", L2cache[addr]);
166 }
167
168 bool isSharer(Addr addr, MachineID requestor, Entry cache_entry) {
169 if (is_valid(cache_entry)) {
170 return cache_entry.Sharers.isElement(requestor);
171 } else {
172 return false;
173 }
174 }
175
176 void addSharer(Addr addr, MachineID requestor, Entry cache_entry) {
177 assert(is_valid(cache_entry));
178 DPRINTF(RubySlicc, "machineID: %s, requestor: %s, address: %#x\n",
179 machineID, requestor, addr);
180 cache_entry.Sharers.add(requestor);
181 }
182
183 State getState(TBE tbe, Entry cache_entry, Addr addr) {
184 if(is_valid(tbe)) {
185 return tbe.TBEState;
186 } else if (is_valid(cache_entry)) {
187 return cache_entry.CacheState;
188 }
189 return State:NP;
190 }
191
192 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
193 // MUST CHANGE
194 if (is_valid(tbe)) {
195 tbe.TBEState := state;
196 }
197
198 if (is_valid(cache_entry)) {
199 cache_entry.CacheState := state;
200 }
201 }
202
203 AccessPermission getAccessPermission(Addr addr) {
204 TBE tbe := TBEs[addr];
205 if(is_valid(tbe)) {
206 DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
207 return L2Cache_State_to_permission(tbe.TBEState);
208 }
209
210 Entry cache_entry := getCacheEntry(addr);
211 if(is_valid(cache_entry)) {
212 DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
213 return L2Cache_State_to_permission(cache_entry.CacheState);
214 }
215
216 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
217 return AccessPermission:NotPresent;
218 }
219
220 void functionalRead(Addr addr, Packet *pkt) {
221 TBE tbe := TBEs[addr];
222 if(is_valid(tbe)) {
223 testAndRead(addr, tbe.DataBlk, pkt);
224 } else {
225 testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
226 }
227 }
228
229 int functionalWrite(Addr addr, Packet *pkt) {
230 int num_functional_writes := 0;
231
232 TBE tbe := TBEs[addr];
233 if(is_valid(tbe)) {
234 num_functional_writes := num_functional_writes +
235 testAndWrite(addr, tbe.DataBlk, pkt);
236 return num_functional_writes;
237 }
238
239 num_functional_writes := num_functional_writes +
240 testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
241 return num_functional_writes;
242 }
243
244 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
245 if (is_valid(cache_entry)) {
246 cache_entry.changePermission(L2Cache_State_to_permission(state));
247 }
248 }
249
250 Event L1Cache_request_type_to_event(CoherenceRequestType type, Addr addr,
251 MachineID requestor, Entry cache_entry) {
252 if(type == CoherenceRequestType:GETS) {
253 return Event:L1_GETS;
254 } else if(type == CoherenceRequestType:GET_INSTR) {
255 return Event:L1_GET_INSTR;
256 } else if (type == CoherenceRequestType:GETX) {
257 return Event:L1_GETX;
258 } else if (type == CoherenceRequestType:UPGRADE) {
259 if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) {
260 return Event:L1_UPGRADE;
261 } else {
262 return Event:L1_GETX;
263 }
264 } else if (type == CoherenceRequestType:PUTX) {
265 if (isSharer(addr, requestor, cache_entry)) {
266 return Event:L1_PUTX;
267 } else {
268 return Event:L1_PUTX_old;
269 }
270 } else {
271 DPRINTF(RubySlicc, "address: %#x, Request Type: %s\n", addr, type);
272 error("Invalid L1 forwarded request type");
273 }
274 }
275
276 int getPendingAcks(TBE tbe) {
277 return tbe.pendingAcks;
278 }
279
280 bool isDirty(Entry cache_entry) {
281 assert(is_valid(cache_entry));
282 return cache_entry.Dirty;
283 }
284
285 // ** OUT_PORTS **
286
287 out_port(L1RequestL2Network_out, RequestMsg, L1RequestFromL2Cache);
288 out_port(DirRequestL2Network_out, RequestMsg, DirRequestFromL2Cache);
289 out_port(responseL2Network_out, ResponseMsg, responseFromL2Cache);
290
291
292 in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache, rank = 2) {
293 if(L1unblockNetwork_in.isReady(clockEdge())) {
294 peek(L1unblockNetwork_in, ResponseMsg) {
295 Entry cache_entry := getCacheEntry(in_msg.addr);
296 TBE tbe := TBEs[in_msg.addr];
297 DPRINTF(RubySlicc, "Addr: %#x State: %s Sender: %s Type: %s Dest: %s\n",
298 in_msg.addr, getState(tbe, cache_entry, in_msg.addr),
299 in_msg.Sender, in_msg.Type, in_msg.Destination);
300
301 assert(in_msg.Destination.isElement(machineID));
302 if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) {
303 trigger(Event:Exclusive_Unblock, in_msg.addr, cache_entry, tbe);
304 } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
305 trigger(Event:Unblock, in_msg.addr, cache_entry, tbe);
306 } else {
307 error("unknown unblock message");
308 }
309 }
310 }
311 }
312
313 // Response L2 Network - response msg to this particular L2 bank
314 in_port(responseL2Network_in, ResponseMsg, responseToL2Cache, rank = 1) {
315 if (responseL2Network_in.isReady(clockEdge())) {
316 peek(responseL2Network_in, ResponseMsg) {
317 // test wether it's from a local L1 or an off chip source
318 assert(in_msg.Destination.isElement(machineID));
319 Entry cache_entry := getCacheEntry(in_msg.addr);
320 TBE tbe := TBEs[in_msg.addr];
321
322 if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
323 if(in_msg.Type == CoherenceResponseType:DATA) {
324 if (in_msg.Dirty) {
325 trigger(Event:WB_Data, in_msg.addr, cache_entry, tbe);
326 } else {
327 trigger(Event:WB_Data_clean, in_msg.addr, cache_entry, tbe);
328 }
329 } else if (in_msg.Type == CoherenceResponseType:ACK) {
330 if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) {
331 trigger(Event:Ack_all, in_msg.addr, cache_entry, tbe);
332 } else {
333 trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
334 }
335 } else {
336 error("unknown message type");
337 }
338
339 } else { // external message
340 if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
341 trigger(Event:Mem_Data, in_msg.addr, cache_entry, tbe);
342 } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) {
343 trigger(Event:Mem_Ack, in_msg.addr, cache_entry, tbe);
344 } else if(in_msg.Type == CoherenceResponseType:INV) {
345 trigger(Event:MEM_Inv, in_msg.addr, cache_entry, tbe);
346 } else {
347 error("unknown message type");
348 }
349 }
350 }
351 } // if not ready, do nothing
352 }
353
354 // L1 Request
355 in_port(L1RequestL2Network_in, RequestMsg, L1RequestToL2Cache, rank = 0) {
356 if(L1RequestL2Network_in.isReady(clockEdge())) {
357 peek(L1RequestL2Network_in, RequestMsg) {
358 Entry cache_entry := getCacheEntry(in_msg.addr);
359 TBE tbe := TBEs[in_msg.addr];
360
361 DPRINTF(RubySlicc, "Addr: %#x State: %s Req: %s Type: %s Dest: %s\n",
362 in_msg.addr, getState(tbe, cache_entry, in_msg.addr),
363 in_msg.Requestor, in_msg.Type, in_msg.Destination);
364
365 assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache);
366 assert(in_msg.Destination.isElement(machineID));
367
368 if (is_valid(cache_entry)) {
369 // The L2 contains the block, so proceeded with handling the request
370 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.addr,
371 in_msg.Requestor, cache_entry),
372 in_msg.addr, cache_entry, tbe);
373 } else {
374 if (L2cache.cacheAvail(in_msg.addr)) {
375 // L2 does't have the line, but we have space for it in the L2
376 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.addr,
377 in_msg.Requestor, cache_entry),
378 in_msg.addr, cache_entry, tbe);
379 } else {
380 // No room in the L2, so we need to make room before handling the request
1/*
2 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29machine(MachineType:L2Cache, "MESI Directory L2 Cache CMP")
30 : CacheMemory * L2cache;
31 Cycles l2_request_latency := 2;
32 Cycles l2_response_latency := 2;
33 Cycles to_l1_latency := 1;
34
35 // Message Queues
36 // From local bank of L2 cache TO the network
37 MessageBuffer * DirRequestFromL2Cache, network="To", virtual_network="0",
38 vnet_type="request"; // this L2 bank -> Memory
39
40 MessageBuffer * L1RequestFromL2Cache, network="To", virtual_network="2",
41 vnet_type="request"; // this L2 bank -> a local L1
42
43 MessageBuffer * responseFromL2Cache, network="To", virtual_network="1",
44 vnet_type="response"; // this L2 bank -> a local L1 || Memory
45
46 // FROM the network to this local bank of L2 cache
47 MessageBuffer * unblockToL2Cache, network="From", virtual_network="2",
48 vnet_type="unblock"; // a local L1 || Memory -> this L2 bank
49
50 MessageBuffer * L1RequestToL2Cache, network="From", virtual_network="0",
51 vnet_type="request"; // a local L1 -> this L2 bank
52
53 MessageBuffer * responseToL2Cache, network="From", virtual_network="1",
54 vnet_type="response"; // a local L1 || Memory -> this L2 bank
55{
56 // STATES
57 state_declaration(State, desc="L2 Cache states", default="L2Cache_State_NP") {
58 // Base states
59 NP, AccessPermission:Invalid, desc="Not present in either cache";
60 SS, AccessPermission:Read_Only, desc="L2 cache entry Shared, also present in one or more L1s";
61 M, AccessPermission:Read_Write, desc="L2 cache entry Modified, not present in any L1s", format="!b";
62 MT, AccessPermission:Maybe_Stale, desc="L2 cache entry Modified in a local L1, assume L2 copy stale", format="!b";
63
64 // L2 replacement
65 M_I, AccessPermission:Busy, desc="L2 cache replacing, have all acks, sent dirty data to memory, waiting for ACK from memory";
66 MT_I, AccessPermission:Busy, desc="L2 cache replacing, getting data from exclusive";
67 MCT_I, AccessPermission:Busy, desc="L2 cache replacing, clean in L2, getting data or ack from exclusive";
68 I_I, AccessPermission:Busy, desc="L2 replacing clean data, need to inv sharers and then drop data";
69 S_I, AccessPermission:Busy, desc="L2 replacing dirty data, collecting acks from L1s";
70
71 // Transient States for fetching data from memory
72 ISS, AccessPermission:Busy, desc="L2 idle, got single L1_GETS, issued memory fetch, have not seen response yet";
73 IS, AccessPermission:Busy, desc="L2 idle, got L1_GET_INSTR or multiple L1_GETS, issued memory fetch, have not seen response yet";
74 IM, AccessPermission:Busy, desc="L2 idle, got L1_GETX, issued memory fetch, have not seen response(s) yet";
75
76 // Blocking states
77 SS_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from SS";
78 MT_MB, AccessPermission:Busy, desc="Blocked for L1_GETX from MT";
79
80 MT_IIB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, waiting for unblock and data";
81 MT_IB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got unblock, waiting for data";
82 MT_SB, AccessPermission:Busy, desc="Blocked for L1_GETS from MT, got data, waiting for unblock";
83
84 }
85
86 // EVENTS
87 enumeration(Event, desc="L2 Cache events") {
88 // L2 events
89
90 // events initiated by the local L1s
91 L1_GET_INSTR, desc="a L1I GET INSTR request for a block maped to us";
92 L1_GETS, desc="a L1D GETS request for a block maped to us";
93 L1_GETX, desc="a L1D GETX request for a block maped to us";
94 L1_UPGRADE, desc="a L1D GETX request for a block maped to us";
95
96 L1_PUTX, desc="L1 replacing data";
97 L1_PUTX_old, desc="L1 replacing data, but no longer sharer";
98
99 // events initiated by this L2
100 L2_Replacement, desc="L2 Replacement", format="!r";
101 L2_Replacement_clean, desc="L2 Replacement, but data is clean", format="!r";
102
103 // events from memory controller
104 Mem_Data, desc="data from memory", format="!r";
105 Mem_Ack, desc="ack from memory", format="!r";
106
107 // M->S data writeback
108 WB_Data, desc="data from L1";
109 WB_Data_clean, desc="clean data from L1";
110 Ack, desc="writeback ack";
111 Ack_all, desc="writeback ack";
112
113 Unblock, desc="Unblock from L1 requestor";
114 Exclusive_Unblock, desc="Unblock from L1 requestor";
115
116 MEM_Inv, desc="Invalidation from directory";
117 }
118
119 // TYPES
120
121 // CacheEntry
122 structure(Entry, desc="...", interface="AbstractCacheEntry") {
123 State CacheState, desc="cache state";
124 NetDest Sharers, desc="tracks the L1 shares on-chip";
125 MachineID Exclusive, desc="Exclusive holder of block";
126 DataBlock DataBlk, desc="data for the block";
127 bool Dirty, default="false", desc="data is dirty";
128 }
129
130 // TBE fields
131 structure(TBE, desc="...") {
132 Addr addr, desc="Physical address for this TBE";
133 State TBEState, desc="Transient state";
134 DataBlock DataBlk, desc="Buffer for the data block";
135 bool Dirty, default="false", desc="Data is Dirty";
136
137 NetDest L1_GetS_IDs, desc="Set of the internal processors that want the block in shared state";
138 MachineID L1_GetX_ID, desc="ID of the L1 cache to forward the block to once we get a response";
139 int pendingAcks, desc="number of pending acks for invalidates during writeback";
140 }
141
142 structure(TBETable, external="yes") {
143 TBE lookup(Addr);
144 void allocate(Addr);
145 void deallocate(Addr);
146 bool isPresent(Addr);
147 }
148
149 TBETable TBEs, template="<L2Cache_TBE>", constructor="m_number_of_TBEs";
150
151 Tick clockEdge();
152 Tick cyclesToTicks(Cycles c);
153 Cycles ticksToCycles(Tick t);
154
155 void set_cache_entry(AbstractCacheEntry a);
156 void unset_cache_entry();
157 void set_tbe(TBE a);
158 void unset_tbe();
159 void wakeUpBuffers(Addr a);
160 void profileMsgDelay(int virtualNetworkType, Cycles c);
161 MachineID mapAddressToMachine(Addr addr, MachineType mtype);
162
163 // inclusive cache, returns L2 entries only
164 Entry getCacheEntry(Addr addr), return_by_pointer="yes" {
165 return static_cast(Entry, "pointer", L2cache[addr]);
166 }
167
168 bool isSharer(Addr addr, MachineID requestor, Entry cache_entry) {
169 if (is_valid(cache_entry)) {
170 return cache_entry.Sharers.isElement(requestor);
171 } else {
172 return false;
173 }
174 }
175
176 void addSharer(Addr addr, MachineID requestor, Entry cache_entry) {
177 assert(is_valid(cache_entry));
178 DPRINTF(RubySlicc, "machineID: %s, requestor: %s, address: %#x\n",
179 machineID, requestor, addr);
180 cache_entry.Sharers.add(requestor);
181 }
182
183 State getState(TBE tbe, Entry cache_entry, Addr addr) {
184 if(is_valid(tbe)) {
185 return tbe.TBEState;
186 } else if (is_valid(cache_entry)) {
187 return cache_entry.CacheState;
188 }
189 return State:NP;
190 }
191
192 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) {
193 // MUST CHANGE
194 if (is_valid(tbe)) {
195 tbe.TBEState := state;
196 }
197
198 if (is_valid(cache_entry)) {
199 cache_entry.CacheState := state;
200 }
201 }
202
203 AccessPermission getAccessPermission(Addr addr) {
204 TBE tbe := TBEs[addr];
205 if(is_valid(tbe)) {
206 DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(tbe.TBEState));
207 return L2Cache_State_to_permission(tbe.TBEState);
208 }
209
210 Entry cache_entry := getCacheEntry(addr);
211 if(is_valid(cache_entry)) {
212 DPRINTF(RubySlicc, "%s\n", L2Cache_State_to_permission(cache_entry.CacheState));
213 return L2Cache_State_to_permission(cache_entry.CacheState);
214 }
215
216 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
217 return AccessPermission:NotPresent;
218 }
219
220 void functionalRead(Addr addr, Packet *pkt) {
221 TBE tbe := TBEs[addr];
222 if(is_valid(tbe)) {
223 testAndRead(addr, tbe.DataBlk, pkt);
224 } else {
225 testAndRead(addr, getCacheEntry(addr).DataBlk, pkt);
226 }
227 }
228
229 int functionalWrite(Addr addr, Packet *pkt) {
230 int num_functional_writes := 0;
231
232 TBE tbe := TBEs[addr];
233 if(is_valid(tbe)) {
234 num_functional_writes := num_functional_writes +
235 testAndWrite(addr, tbe.DataBlk, pkt);
236 return num_functional_writes;
237 }
238
239 num_functional_writes := num_functional_writes +
240 testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt);
241 return num_functional_writes;
242 }
243
244 void setAccessPermission(Entry cache_entry, Addr addr, State state) {
245 if (is_valid(cache_entry)) {
246 cache_entry.changePermission(L2Cache_State_to_permission(state));
247 }
248 }
249
250 Event L1Cache_request_type_to_event(CoherenceRequestType type, Addr addr,
251 MachineID requestor, Entry cache_entry) {
252 if(type == CoherenceRequestType:GETS) {
253 return Event:L1_GETS;
254 } else if(type == CoherenceRequestType:GET_INSTR) {
255 return Event:L1_GET_INSTR;
256 } else if (type == CoherenceRequestType:GETX) {
257 return Event:L1_GETX;
258 } else if (type == CoherenceRequestType:UPGRADE) {
259 if ( is_valid(cache_entry) && cache_entry.Sharers.isElement(requestor) ) {
260 return Event:L1_UPGRADE;
261 } else {
262 return Event:L1_GETX;
263 }
264 } else if (type == CoherenceRequestType:PUTX) {
265 if (isSharer(addr, requestor, cache_entry)) {
266 return Event:L1_PUTX;
267 } else {
268 return Event:L1_PUTX_old;
269 }
270 } else {
271 DPRINTF(RubySlicc, "address: %#x, Request Type: %s\n", addr, type);
272 error("Invalid L1 forwarded request type");
273 }
274 }
275
276 int getPendingAcks(TBE tbe) {
277 return tbe.pendingAcks;
278 }
279
280 bool isDirty(Entry cache_entry) {
281 assert(is_valid(cache_entry));
282 return cache_entry.Dirty;
283 }
284
285 // ** OUT_PORTS **
286
287 out_port(L1RequestL2Network_out, RequestMsg, L1RequestFromL2Cache);
288 out_port(DirRequestL2Network_out, RequestMsg, DirRequestFromL2Cache);
289 out_port(responseL2Network_out, ResponseMsg, responseFromL2Cache);
290
291
292 in_port(L1unblockNetwork_in, ResponseMsg, unblockToL2Cache, rank = 2) {
293 if(L1unblockNetwork_in.isReady(clockEdge())) {
294 peek(L1unblockNetwork_in, ResponseMsg) {
295 Entry cache_entry := getCacheEntry(in_msg.addr);
296 TBE tbe := TBEs[in_msg.addr];
297 DPRINTF(RubySlicc, "Addr: %#x State: %s Sender: %s Type: %s Dest: %s\n",
298 in_msg.addr, getState(tbe, cache_entry, in_msg.addr),
299 in_msg.Sender, in_msg.Type, in_msg.Destination);
300
301 assert(in_msg.Destination.isElement(machineID));
302 if (in_msg.Type == CoherenceResponseType:EXCLUSIVE_UNBLOCK) {
303 trigger(Event:Exclusive_Unblock, in_msg.addr, cache_entry, tbe);
304 } else if (in_msg.Type == CoherenceResponseType:UNBLOCK) {
305 trigger(Event:Unblock, in_msg.addr, cache_entry, tbe);
306 } else {
307 error("unknown unblock message");
308 }
309 }
310 }
311 }
312
313 // Response L2 Network - response msg to this particular L2 bank
314 in_port(responseL2Network_in, ResponseMsg, responseToL2Cache, rank = 1) {
315 if (responseL2Network_in.isReady(clockEdge())) {
316 peek(responseL2Network_in, ResponseMsg) {
317 // test wether it's from a local L1 or an off chip source
318 assert(in_msg.Destination.isElement(machineID));
319 Entry cache_entry := getCacheEntry(in_msg.addr);
320 TBE tbe := TBEs[in_msg.addr];
321
322 if(machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) {
323 if(in_msg.Type == CoherenceResponseType:DATA) {
324 if (in_msg.Dirty) {
325 trigger(Event:WB_Data, in_msg.addr, cache_entry, tbe);
326 } else {
327 trigger(Event:WB_Data_clean, in_msg.addr, cache_entry, tbe);
328 }
329 } else if (in_msg.Type == CoherenceResponseType:ACK) {
330 if ((getPendingAcks(tbe) - in_msg.AckCount) == 0) {
331 trigger(Event:Ack_all, in_msg.addr, cache_entry, tbe);
332 } else {
333 trigger(Event:Ack, in_msg.addr, cache_entry, tbe);
334 }
335 } else {
336 error("unknown message type");
337 }
338
339 } else { // external message
340 if(in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
341 trigger(Event:Mem_Data, in_msg.addr, cache_entry, tbe);
342 } else if(in_msg.Type == CoherenceResponseType:MEMORY_ACK) {
343 trigger(Event:Mem_Ack, in_msg.addr, cache_entry, tbe);
344 } else if(in_msg.Type == CoherenceResponseType:INV) {
345 trigger(Event:MEM_Inv, in_msg.addr, cache_entry, tbe);
346 } else {
347 error("unknown message type");
348 }
349 }
350 }
351 } // if not ready, do nothing
352 }
353
354 // L1 Request
355 in_port(L1RequestL2Network_in, RequestMsg, L1RequestToL2Cache, rank = 0) {
356 if(L1RequestL2Network_in.isReady(clockEdge())) {
357 peek(L1RequestL2Network_in, RequestMsg) {
358 Entry cache_entry := getCacheEntry(in_msg.addr);
359 TBE tbe := TBEs[in_msg.addr];
360
361 DPRINTF(RubySlicc, "Addr: %#x State: %s Req: %s Type: %s Dest: %s\n",
362 in_msg.addr, getState(tbe, cache_entry, in_msg.addr),
363 in_msg.Requestor, in_msg.Type, in_msg.Destination);
364
365 assert(machineIDToMachineType(in_msg.Requestor) == MachineType:L1Cache);
366 assert(in_msg.Destination.isElement(machineID));
367
368 if (is_valid(cache_entry)) {
369 // The L2 contains the block, so proceeded with handling the request
370 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.addr,
371 in_msg.Requestor, cache_entry),
372 in_msg.addr, cache_entry, tbe);
373 } else {
374 if (L2cache.cacheAvail(in_msg.addr)) {
375 // L2 does't have the line, but we have space for it in the L2
376 trigger(L1Cache_request_type_to_event(in_msg.Type, in_msg.addr,
377 in_msg.Requestor, cache_entry),
378 in_msg.addr, cache_entry, tbe);
379 } else {
380 // No room in the L2, so we need to make room before handling the request
381 Entry L2cache_entry := getCacheEntry(L2cache.cacheProbe(in_msg.addr));
381 Addr victim := L2cache.cacheProbe(in_msg.addr);
382 Entry L2cache_entry := getCacheEntry(victim);
382 if (isDirty(L2cache_entry)) {
383 if (isDirty(L2cache_entry)) {
383 trigger(Event:L2_Replacement, L2cache.cacheProbe(in_msg.addr),
384 L2cache_entry, TBEs[L2cache.cacheProbe(in_msg.addr)]);
384 trigger(Event:L2_Replacement, victim, L2cache_entry, TBEs[victim]);
385 } else {
385 } else {
386 trigger(Event:L2_Replacement_clean, L2cache.cacheProbe(in_msg.addr),
387 L2cache_entry, TBEs[L2cache.cacheProbe(in_msg.addr)]);
386 trigger(Event:L2_Replacement_clean,
387 victim, L2cache_entry, TBEs[victim]);
388 }
389 }
390 }
391 }
392 }
393 }
394
395
396 // ACTIONS
397
398 action(a_issueFetchToMemory, "a", desc="fetch data from memory") {
399 peek(L1RequestL2Network_in, RequestMsg) {
400 enqueue(DirRequestL2Network_out, RequestMsg, l2_request_latency) {
401 out_msg.addr := address;
402 out_msg.Type := CoherenceRequestType:GETS;
403 out_msg.Requestor := machineID;
404 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
405 out_msg.MessageSize := MessageSizeType:Control;
406 }
407 }
408 }
409
410 action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") {
411 peek(L1RequestL2Network_in, RequestMsg) {
412 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
413 assert(is_valid(cache_entry));
414 out_msg.addr := address;
415 out_msg.Type := in_msg.Type;
416 out_msg.Requestor := in_msg.Requestor;
417 out_msg.Destination.add(cache_entry.Exclusive);
418 out_msg.MessageSize := MessageSizeType:Request_Control;
419 }
420 }
421 }
422
423 action(c_exclusiveReplacement, "c", desc="Send data to memory") {
424 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
425 assert(is_valid(cache_entry));
426 out_msg.addr := address;
427 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
428 out_msg.Sender := machineID;
429 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
430 out_msg.DataBlk := cache_entry.DataBlk;
431 out_msg.Dirty := cache_entry.Dirty;
432 out_msg.MessageSize := MessageSizeType:Response_Data;
433 }
434 }
435
436 action(c_exclusiveCleanReplacement, "cc", desc="Send ack to memory for clean replacement") {
437 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
438 out_msg.addr := address;
439 out_msg.Type := CoherenceResponseType:ACK;
440 out_msg.Sender := machineID;
441 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
442 out_msg.MessageSize := MessageSizeType:Response_Control;
443 }
444 }
445
446 action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") {
447 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
448 assert(is_valid(tbe));
449 out_msg.addr := address;
450 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
451 out_msg.Sender := machineID;
452 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
453 out_msg.DataBlk := tbe.DataBlk;
454 out_msg.Dirty := tbe.Dirty;
455 out_msg.MessageSize := MessageSizeType:Response_Data;
456 }
457 }
458
459 action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") {
460 peek(L1RequestL2Network_in, RequestMsg) {
461 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
462 assert(is_valid(cache_entry));
463 out_msg.addr := address;
464 out_msg.Type := CoherenceResponseType:DATA;
465 out_msg.Sender := machineID;
466 out_msg.Destination.add(in_msg.Requestor);
467 out_msg.DataBlk := cache_entry.DataBlk;
468 out_msg.MessageSize := MessageSizeType:Response_Data;
469
470 out_msg.AckCount := 0 - cache_entry.Sharers.count();
471 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
472 out_msg.AckCount := out_msg.AckCount + 1;
473 }
474 }
475 }
476 }
477
478 action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") {
479 peek(L1RequestL2Network_in, RequestMsg) {
480 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
481 assert(is_valid(cache_entry));
482 out_msg.addr := address;
483 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
484 out_msg.Sender := machineID;
485 out_msg.Destination.add(in_msg.Requestor);
486 out_msg.DataBlk := cache_entry.DataBlk;
487 out_msg.MessageSize := MessageSizeType:Response_Data;
488
489 out_msg.AckCount := 0 - cache_entry.Sharers.count();
490 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
491 out_msg.AckCount := out_msg.AckCount + 1;
492 }
493 }
494 }
495 }
496
497 action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") {
498 peek(L1RequestL2Network_in, RequestMsg) {
499 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
500 assert(is_valid(cache_entry));
501 out_msg.addr := address;
502 out_msg.Type := CoherenceResponseType:DATA;
503 out_msg.Sender := machineID;
504 out_msg.Destination.add(in_msg.Requestor);
505 out_msg.DataBlk := cache_entry.DataBlk;
506 out_msg.MessageSize := MessageSizeType:Response_Data;
507 out_msg.AckCount := 0;
508 }
509 }
510 }
511
512 action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") {
513 assert(is_valid(tbe));
514 assert(tbe.L1_GetS_IDs.count() > 0);
515 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
516 assert(is_valid(cache_entry));
517 out_msg.addr := address;
518 out_msg.Type := CoherenceResponseType:DATA;
519 out_msg.Sender := machineID;
520 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
521 out_msg.DataBlk := cache_entry.DataBlk;
522 out_msg.MessageSize := MessageSizeType:Response_Data;
523 }
524 }
525
526 action(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") {
527 assert(is_valid(tbe));
528 assert(tbe.L1_GetS_IDs.count() == 1);
529 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
530 assert(is_valid(cache_entry));
531 out_msg.addr := address;
532 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
533 out_msg.Sender := machineID;
534 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
535 out_msg.DataBlk := cache_entry.DataBlk;
536 out_msg.MessageSize := MessageSizeType:Response_Data;
537 }
538 }
539
540 action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") {
541 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
542 assert(is_valid(tbe));
543 assert(is_valid(cache_entry));
544 out_msg.addr := address;
545 out_msg.Type := CoherenceResponseType:DATA;
546 out_msg.Sender := machineID;
547 out_msg.Destination.add(tbe.L1_GetX_ID);
548 DPRINTF(RubySlicc, "%s\n", out_msg.Destination);
549 out_msg.DataBlk := cache_entry.DataBlk;
550 DPRINTF(RubySlicc, "Address: %#x, Destination: %s, DataBlock: %s\n",
551 out_msg.addr, out_msg.Destination, out_msg.DataBlk);
552 out_msg.MessageSize := MessageSizeType:Response_Data;
553 }
554 }
555
556 action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") {
557 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
558 assert(is_valid(cache_entry));
559 out_msg.addr := address;
560 out_msg.Type := CoherenceRequestType:INV;
561 out_msg.Requestor := machineID;
562 out_msg.Destination := cache_entry.Sharers;
563 out_msg.MessageSize := MessageSizeType:Request_Control;
564 }
565 }
566
567 action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") {
568 peek(L1RequestL2Network_in, RequestMsg) {
569 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
570 assert(is_valid(cache_entry));
571 out_msg.addr := address;
572 out_msg.Type := CoherenceRequestType:INV;
573 out_msg.Requestor := in_msg.Requestor;
574 out_msg.Destination := cache_entry.Sharers;
575 out_msg.MessageSize := MessageSizeType:Request_Control;
576 }
577 }
578 }
579
580 action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") {
581 peek(L1RequestL2Network_in, RequestMsg) {
582 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
583 assert(is_valid(cache_entry));
584 out_msg.addr := address;
585 out_msg.Type := CoherenceRequestType:INV;
586 out_msg.Requestor := in_msg.Requestor;
587 out_msg.Destination := cache_entry.Sharers;
588 out_msg.Destination.remove(in_msg.Requestor);
589 out_msg.MessageSize := MessageSizeType:Request_Control;
590 }
591 }
592 }
593
594 // OTHER ACTIONS
595 action(i_allocateTBE, "i", desc="Allocate TBE for request") {
596 check_allocate(TBEs);
597 assert(is_valid(cache_entry));
598 TBEs.allocate(address);
599 set_tbe(TBEs[address]);
600 tbe.L1_GetS_IDs.clear();
601 tbe.DataBlk := cache_entry.DataBlk;
602 tbe.Dirty := cache_entry.Dirty;
603 tbe.pendingAcks := cache_entry.Sharers.count();
604 }
605
606 action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
607 TBEs.deallocate(address);
608 unset_tbe();
609 }
610
611 action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
612 Tick delay := L1RequestL2Network_in.dequeue(clockEdge());
613 profileMsgDelay(0, ticksToCycles(delay));
614 }
615
616 action(k_popUnblockQueue, "k", desc="Pop incoming unblock queue") {
617 Tick delay := L1unblockNetwork_in.dequeue(clockEdge());
618 profileMsgDelay(0, ticksToCycles(delay));
619 }
620
621 action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
622 Tick delay := responseL2Network_in.dequeue(clockEdge());
623 profileMsgDelay(1, ticksToCycles(delay));
624 }
625
626 action(m_writeDataToCache, "m", desc="Write data from response queue to cache") {
627 peek(responseL2Network_in, ResponseMsg) {
628 assert(is_valid(cache_entry));
629 cache_entry.DataBlk := in_msg.DataBlk;
630 if (in_msg.Dirty) {
631 cache_entry.Dirty := in_msg.Dirty;
632 }
633 }
634 }
635
636 action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") {
637 peek(L1RequestL2Network_in, RequestMsg) {
638 assert(is_valid(cache_entry));
639 if (in_msg.Dirty) {
640 cache_entry.DataBlk := in_msg.DataBlk;
641 cache_entry.Dirty := in_msg.Dirty;
642 }
643 }
644 }
645
646 action(q_updateAck, "q", desc="update pending ack count") {
647 peek(responseL2Network_in, ResponseMsg) {
648 assert(is_valid(tbe));
649 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
650 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
651 APPEND_TRANSITION_COMMENT(" p: ");
652 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
653 }
654 }
655
656 action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") {
657 peek(responseL2Network_in, ResponseMsg) {
658 assert(is_valid(tbe));
659 tbe.DataBlk := in_msg.DataBlk;
660 tbe.Dirty := in_msg.Dirty;
661 }
662 }
663
664 action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") {
665 peek(L1RequestL2Network_in, RequestMsg) {
666 assert(is_valid(tbe));
667 tbe.L1_GetS_IDs.add(in_msg.Requestor);
668 }
669 }
670
671 action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
672 peek(L1RequestL2Network_in, RequestMsg) {
673 assert(is_valid(tbe));
674 tbe.L1_GetX_ID := in_msg.Requestor;
675 }
676 }
677
678 action(set_setMRU, "\set", desc="set the MRU entry") {
679 L2cache.setMRU(address);
680 }
681
682 action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
683 if (is_invalid(cache_entry)) {
684 set_cache_entry(L2cache.allocate(address, new Entry));
685 }
686 }
687
688 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
689 L2cache.deallocate(address);
690 unset_cache_entry();
691 }
692
693 action(t_sendWBAck, "t", desc="Send writeback ACK") {
694 peek(L1RequestL2Network_in, RequestMsg) {
695 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
696 out_msg.addr := address;
697 out_msg.Type := CoherenceResponseType:WB_ACK;
698 out_msg.Sender := machineID;
699 out_msg.Destination.add(in_msg.Requestor);
700 out_msg.MessageSize := MessageSizeType:Response_Control;
701 }
702 }
703 }
704
705 action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") {
706 peek(L1RequestL2Network_in, RequestMsg) {
707 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
708 assert(is_valid(cache_entry));
709 out_msg.addr := address;
710 out_msg.Type := CoherenceResponseType:ACK;
711 out_msg.Sender := machineID;
712 out_msg.Destination.add(in_msg.Requestor);
713 out_msg.MessageSize := MessageSizeType:Response_Control;
714 // upgrader doesn't get ack from itself, hence the + 1
715 out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1;
716 }
717 }
718 }
719
720 action(uu_profileMiss, "\um", desc="Profile the demand miss") {
721 ++L2cache.demand_misses;
722 }
723
724 action(uu_profileHit, "\uh", desc="Profile the demand hit") {
725 ++L2cache.demand_hits;
726 }
727
728 action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
729 peek(L1RequestL2Network_in, RequestMsg) {
730 assert(is_valid(cache_entry));
731 addSharer(address, in_msg.Requestor, cache_entry);
732 APPEND_TRANSITION_COMMENT( cache_entry.Sharers );
733 }
734 }
735
736 action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") {
737 peek(L1unblockNetwork_in, ResponseMsg) {
738 assert(is_valid(cache_entry));
739 addSharer(address, in_msg.Sender, cache_entry);
740 }
741 }
742
743 action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
744 peek(L1RequestL2Network_in, RequestMsg) {
745 assert(is_valid(cache_entry));
746 cache_entry.Sharers.remove(in_msg.Requestor);
747 }
748 }
749
750 action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
751 peek(L1RequestL2Network_in, RequestMsg) {
752 assert(is_valid(cache_entry));
753 cache_entry.Sharers.clear();
754 }
755 }
756
757 action(mm_markExclusive, "\m", desc="set the exclusive owner") {
758 peek(L1RequestL2Network_in, RequestMsg) {
759 assert(is_valid(cache_entry));
760 cache_entry.Sharers.clear();
761 cache_entry.Exclusive := in_msg.Requestor;
762 addSharer(address, in_msg.Requestor, cache_entry);
763 }
764 }
765
766 action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") {
767 peek(L1unblockNetwork_in, ResponseMsg) {
768 assert(is_valid(cache_entry));
769 cache_entry.Sharers.clear();
770 cache_entry.Exclusive := in_msg.Sender;
771 addSharer(address, in_msg.Sender, cache_entry);
772 }
773 }
774
775 action(zz_stallAndWaitL1RequestQueue, "zz", desc="recycle L1 request queue") {
776 stall_and_wait(L1RequestL2Network_in, address);
777 }
778
779 action(zn_recycleResponseNetwork, "zn", desc="recycle memory request") {
780 responseL2Network_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
781 }
782
783 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
784 wakeUpBuffers(address);
785 }
786
787 //*****************************************************
788 // TRANSITIONS
789 //*****************************************************
790
791
792 //===============================================
793 // BASE STATE - I
794
795 // Transitions from I (Idle)
796 transition({NP, IS, ISS, IM, SS, M, M_I, I_I, S_I, MT_IB, MT_SB}, L1_PUTX) {
797 t_sendWBAck;
798 jj_popL1RequestQueue;
799 }
800
801 transition({NP, SS, M, MT, M_I, I_I, S_I, IS, ISS, IM, MT_IB, MT_SB}, L1_PUTX_old) {
802 t_sendWBAck;
803 jj_popL1RequestQueue;
804 }
805
806 transition({IM, IS, ISS, SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L2_Replacement, L2_Replacement_clean}) {
807 zz_stallAndWaitL1RequestQueue;
808 }
809
810 transition({IM, IS, ISS, SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, MEM_Inv) {
811 zn_recycleResponseNetwork;
812 }
813
814 transition({I_I, S_I, M_I, MT_I, MCT_I, NP}, MEM_Inv) {
815 o_popIncomingResponseQueue;
816 }
817
818
819 transition({SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE}) {
820 zz_stallAndWaitL1RequestQueue;
821 }
822
823
824 transition(NP, L1_GETS, ISS) {
825 qq_allocateL2CacheBlock;
826 ll_clearSharers;
827 nn_addSharer;
828 i_allocateTBE;
829 ss_recordGetSL1ID;
830 a_issueFetchToMemory;
831 uu_profileMiss;
832 jj_popL1RequestQueue;
833 }
834
835 transition(NP, L1_GET_INSTR, IS) {
836 qq_allocateL2CacheBlock;
837 ll_clearSharers;
838 nn_addSharer;
839 i_allocateTBE;
840 ss_recordGetSL1ID;
841 a_issueFetchToMemory;
842 uu_profileMiss;
843 jj_popL1RequestQueue;
844 }
845
846 transition(NP, L1_GETX, IM) {
847 qq_allocateL2CacheBlock;
848 ll_clearSharers;
849 // nn_addSharer;
850 i_allocateTBE;
851 xx_recordGetXL1ID;
852 a_issueFetchToMemory;
853 uu_profileMiss;
854 jj_popL1RequestQueue;
855 }
856
857
858 // transitions from IS/IM
859
860 transition(ISS, Mem_Data, MT_MB) {
861 m_writeDataToCache;
862 ex_sendExclusiveDataToGetSRequestors;
863 s_deallocateTBE;
864 o_popIncomingResponseQueue;
865 }
866
867 transition(IS, Mem_Data, SS) {
868 m_writeDataToCache;
869 e_sendDataToGetSRequestors;
870 s_deallocateTBE;
871 o_popIncomingResponseQueue;
872 kd_wakeUpDependents;
873 }
874
875 transition(IM, Mem_Data, MT_MB) {
876 m_writeDataToCache;
877 ee_sendDataToGetXRequestor;
878 s_deallocateTBE;
879 o_popIncomingResponseQueue;
880 }
881
882 transition({IS, ISS}, {L1_GETS, L1_GET_INSTR}, IS) {
883 nn_addSharer;
884 ss_recordGetSL1ID;
885 uu_profileMiss;
886 jj_popL1RequestQueue;
887 }
888
889 transition({IS, ISS}, L1_GETX) {
890 zz_stallAndWaitL1RequestQueue;
891 }
892
893 transition(IM, {L1_GETX, L1_GETS, L1_GET_INSTR}) {
894 zz_stallAndWaitL1RequestQueue;
895 }
896
897 // transitions from SS
898 transition(SS, {L1_GETS, L1_GET_INSTR}) {
899 ds_sendSharedDataToRequestor;
900 nn_addSharer;
901 set_setMRU;
902 uu_profileHit;
903 jj_popL1RequestQueue;
904 }
905
906
907 transition(SS, L1_GETX, SS_MB) {
908 d_sendDataToRequestor;
909 // fw_sendFwdInvToSharers;
910 fwm_sendFwdInvToSharersMinusRequestor;
911 set_setMRU;
912 uu_profileHit;
913 jj_popL1RequestQueue;
914 }
915
916 transition(SS, L1_UPGRADE, SS_MB) {
917 fwm_sendFwdInvToSharersMinusRequestor;
918 ts_sendInvAckToUpgrader;
919 set_setMRU;
920 uu_profileHit;
921 jj_popL1RequestQueue;
922 }
923
924 transition(SS, L2_Replacement_clean, I_I) {
925 i_allocateTBE;
926 f_sendInvToSharers;
927 rr_deallocateL2CacheBlock;
928 }
929
930 transition(SS, {L2_Replacement, MEM_Inv}, S_I) {
931 i_allocateTBE;
932 f_sendInvToSharers;
933 rr_deallocateL2CacheBlock;
934 }
935
936
937 transition(M, L1_GETX, MT_MB) {
938 d_sendDataToRequestor;
939 set_setMRU;
940 uu_profileHit;
941 jj_popL1RequestQueue;
942 }
943
944 transition(M, L1_GET_INSTR, SS) {
945 d_sendDataToRequestor;
946 nn_addSharer;
947 set_setMRU;
948 uu_profileHit;
949 jj_popL1RequestQueue;
950 }
951
952 transition(M, L1_GETS, MT_MB) {
953 dd_sendExclusiveDataToRequestor;
954 set_setMRU;
955 uu_profileHit;
956 jj_popL1RequestQueue;
957 }
958
959 transition(M, {L2_Replacement, MEM_Inv}, M_I) {
960 i_allocateTBE;
961 c_exclusiveReplacement;
962 rr_deallocateL2CacheBlock;
963 }
964
965 transition(M, L2_Replacement_clean, M_I) {
966 i_allocateTBE;
967 c_exclusiveCleanReplacement;
968 rr_deallocateL2CacheBlock;
969 }
970
971
972 // transitions from MT
973
974 transition(MT, L1_GETX, MT_MB) {
975 b_forwardRequestToExclusive;
976 uu_profileMiss;
977 set_setMRU;
978 jj_popL1RequestQueue;
979 }
980
981
982 transition(MT, {L1_GETS, L1_GET_INSTR}, MT_IIB) {
983 b_forwardRequestToExclusive;
984 uu_profileMiss;
985 set_setMRU;
986 jj_popL1RequestQueue;
987 }
988
989 transition(MT, {L2_Replacement, MEM_Inv}, MT_I) {
990 i_allocateTBE;
991 f_sendInvToSharers;
992 rr_deallocateL2CacheBlock;
993 }
994
995 transition(MT, L2_Replacement_clean, MCT_I) {
996 i_allocateTBE;
997 f_sendInvToSharers;
998 rr_deallocateL2CacheBlock;
999 }
1000
1001 transition(MT, L1_PUTX, M) {
1002 ll_clearSharers;
1003 mr_writeDataToCacheFromRequest;
1004 t_sendWBAck;
1005 jj_popL1RequestQueue;
1006 }
1007
1008 transition({SS_MB,MT_MB}, Exclusive_Unblock, MT) {
1009 // update actual directory
1010 mmu_markExclusiveFromUnblock;
1011 k_popUnblockQueue;
1012 kd_wakeUpDependents;
1013 }
1014
1015 transition(MT_IIB, {L1_PUTX, L1_PUTX_old}){
1016 zz_stallAndWaitL1RequestQueue;
1017 }
1018
1019 transition(MT_IIB, Unblock, MT_IB) {
1020 nnu_addSharerFromUnblock;
1021 k_popUnblockQueue;
1022 }
1023
1024 transition(MT_IIB, {WB_Data, WB_Data_clean}, MT_SB) {
1025 m_writeDataToCache;
1026 o_popIncomingResponseQueue;
1027 }
1028
1029 transition(MT_IB, {WB_Data, WB_Data_clean}, SS) {
1030 m_writeDataToCache;
1031 o_popIncomingResponseQueue;
1032 kd_wakeUpDependents;
1033 }
1034
1035 transition(MT_SB, Unblock, SS) {
1036 nnu_addSharerFromUnblock;
1037 k_popUnblockQueue;
1038 kd_wakeUpDependents;
1039 }
1040
1041 // writeback states
1042 transition({I_I, S_I, MT_I, MCT_I, M_I}, {L1_GETX, L1_UPGRADE, L1_GETS, L1_GET_INSTR}) {
1043 zz_stallAndWaitL1RequestQueue;
1044 }
1045
1046 transition(I_I, Ack) {
1047 q_updateAck;
1048 o_popIncomingResponseQueue;
1049 }
1050
1051 transition(I_I, Ack_all, M_I) {
1052 c_exclusiveCleanReplacement;
1053 o_popIncomingResponseQueue;
1054 }
1055
1056 transition({MT_I, MCT_I}, WB_Data, M_I) {
1057 qq_writeDataToTBE;
1058 ct_exclusiveReplacementFromTBE;
1059 o_popIncomingResponseQueue;
1060 }
1061
1062 transition(MCT_I, {WB_Data_clean, Ack_all}, M_I) {
1063 c_exclusiveCleanReplacement;
1064 o_popIncomingResponseQueue;
1065 }
1066
1067 transition(MCT_I, {L1_PUTX, L1_PUTX_old}){
1068 zz_stallAndWaitL1RequestQueue;
1069 }
1070
1071 // L1 never changed Dirty data
1072 transition(MT_I, {WB_Data_clean, Ack_all}, M_I) {
1073 ct_exclusiveReplacementFromTBE;
1074 o_popIncomingResponseQueue;
1075 }
1076
1077 transition(MT_I, {L1_PUTX, L1_PUTX_old}){
1078 zz_stallAndWaitL1RequestQueue;
1079 }
1080
1081 // possible race between unblock and immediate replacement
1082 transition({MT_MB,SS_MB}, {L1_PUTX, L1_PUTX_old}) {
1083 zz_stallAndWaitL1RequestQueue;
1084 }
1085
1086 transition(S_I, Ack) {
1087 q_updateAck;
1088 o_popIncomingResponseQueue;
1089 }
1090
1091 transition(S_I, Ack_all, M_I) {
1092 ct_exclusiveReplacementFromTBE;
1093 o_popIncomingResponseQueue;
1094 }
1095
1096 transition(M_I, Mem_Ack, NP) {
1097 s_deallocateTBE;
1098 o_popIncomingResponseQueue;
1099 kd_wakeUpDependents;
1100 }
1101}
388 }
389 }
390 }
391 }
392 }
393 }
394
395
396 // ACTIONS
397
398 action(a_issueFetchToMemory, "a", desc="fetch data from memory") {
399 peek(L1RequestL2Network_in, RequestMsg) {
400 enqueue(DirRequestL2Network_out, RequestMsg, l2_request_latency) {
401 out_msg.addr := address;
402 out_msg.Type := CoherenceRequestType:GETS;
403 out_msg.Requestor := machineID;
404 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
405 out_msg.MessageSize := MessageSizeType:Control;
406 }
407 }
408 }
409
410 action(b_forwardRequestToExclusive, "b", desc="Forward request to the exclusive L1") {
411 peek(L1RequestL2Network_in, RequestMsg) {
412 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
413 assert(is_valid(cache_entry));
414 out_msg.addr := address;
415 out_msg.Type := in_msg.Type;
416 out_msg.Requestor := in_msg.Requestor;
417 out_msg.Destination.add(cache_entry.Exclusive);
418 out_msg.MessageSize := MessageSizeType:Request_Control;
419 }
420 }
421 }
422
423 action(c_exclusiveReplacement, "c", desc="Send data to memory") {
424 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
425 assert(is_valid(cache_entry));
426 out_msg.addr := address;
427 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
428 out_msg.Sender := machineID;
429 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
430 out_msg.DataBlk := cache_entry.DataBlk;
431 out_msg.Dirty := cache_entry.Dirty;
432 out_msg.MessageSize := MessageSizeType:Response_Data;
433 }
434 }
435
436 action(c_exclusiveCleanReplacement, "cc", desc="Send ack to memory for clean replacement") {
437 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
438 out_msg.addr := address;
439 out_msg.Type := CoherenceResponseType:ACK;
440 out_msg.Sender := machineID;
441 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
442 out_msg.MessageSize := MessageSizeType:Response_Control;
443 }
444 }
445
446 action(ct_exclusiveReplacementFromTBE, "ct", desc="Send data to memory") {
447 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
448 assert(is_valid(tbe));
449 out_msg.addr := address;
450 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
451 out_msg.Sender := machineID;
452 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory));
453 out_msg.DataBlk := tbe.DataBlk;
454 out_msg.Dirty := tbe.Dirty;
455 out_msg.MessageSize := MessageSizeType:Response_Data;
456 }
457 }
458
459 action(d_sendDataToRequestor, "d", desc="Send data from cache to reqeustor") {
460 peek(L1RequestL2Network_in, RequestMsg) {
461 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
462 assert(is_valid(cache_entry));
463 out_msg.addr := address;
464 out_msg.Type := CoherenceResponseType:DATA;
465 out_msg.Sender := machineID;
466 out_msg.Destination.add(in_msg.Requestor);
467 out_msg.DataBlk := cache_entry.DataBlk;
468 out_msg.MessageSize := MessageSizeType:Response_Data;
469
470 out_msg.AckCount := 0 - cache_entry.Sharers.count();
471 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
472 out_msg.AckCount := out_msg.AckCount + 1;
473 }
474 }
475 }
476 }
477
478 action(dd_sendExclusiveDataToRequestor, "dd", desc="Send data from cache to reqeustor") {
479 peek(L1RequestL2Network_in, RequestMsg) {
480 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
481 assert(is_valid(cache_entry));
482 out_msg.addr := address;
483 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
484 out_msg.Sender := machineID;
485 out_msg.Destination.add(in_msg.Requestor);
486 out_msg.DataBlk := cache_entry.DataBlk;
487 out_msg.MessageSize := MessageSizeType:Response_Data;
488
489 out_msg.AckCount := 0 - cache_entry.Sharers.count();
490 if (cache_entry.Sharers.isElement(in_msg.Requestor)) {
491 out_msg.AckCount := out_msg.AckCount + 1;
492 }
493 }
494 }
495 }
496
497 action(ds_sendSharedDataToRequestor, "ds", desc="Send data from cache to reqeustor") {
498 peek(L1RequestL2Network_in, RequestMsg) {
499 enqueue(responseL2Network_out, ResponseMsg, l2_response_latency) {
500 assert(is_valid(cache_entry));
501 out_msg.addr := address;
502 out_msg.Type := CoherenceResponseType:DATA;
503 out_msg.Sender := machineID;
504 out_msg.Destination.add(in_msg.Requestor);
505 out_msg.DataBlk := cache_entry.DataBlk;
506 out_msg.MessageSize := MessageSizeType:Response_Data;
507 out_msg.AckCount := 0;
508 }
509 }
510 }
511
512 action(e_sendDataToGetSRequestors, "e", desc="Send data from cache to all GetS IDs") {
513 assert(is_valid(tbe));
514 assert(tbe.L1_GetS_IDs.count() > 0);
515 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
516 assert(is_valid(cache_entry));
517 out_msg.addr := address;
518 out_msg.Type := CoherenceResponseType:DATA;
519 out_msg.Sender := machineID;
520 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
521 out_msg.DataBlk := cache_entry.DataBlk;
522 out_msg.MessageSize := MessageSizeType:Response_Data;
523 }
524 }
525
526 action(ex_sendExclusiveDataToGetSRequestors, "ex", desc="Send data from cache to all GetS IDs") {
527 assert(is_valid(tbe));
528 assert(tbe.L1_GetS_IDs.count() == 1);
529 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
530 assert(is_valid(cache_entry));
531 out_msg.addr := address;
532 out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
533 out_msg.Sender := machineID;
534 out_msg.Destination := tbe.L1_GetS_IDs; // internal nodes
535 out_msg.DataBlk := cache_entry.DataBlk;
536 out_msg.MessageSize := MessageSizeType:Response_Data;
537 }
538 }
539
540 action(ee_sendDataToGetXRequestor, "ee", desc="Send data from cache to GetX ID") {
541 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
542 assert(is_valid(tbe));
543 assert(is_valid(cache_entry));
544 out_msg.addr := address;
545 out_msg.Type := CoherenceResponseType:DATA;
546 out_msg.Sender := machineID;
547 out_msg.Destination.add(tbe.L1_GetX_ID);
548 DPRINTF(RubySlicc, "%s\n", out_msg.Destination);
549 out_msg.DataBlk := cache_entry.DataBlk;
550 DPRINTF(RubySlicc, "Address: %#x, Destination: %s, DataBlock: %s\n",
551 out_msg.addr, out_msg.Destination, out_msg.DataBlk);
552 out_msg.MessageSize := MessageSizeType:Response_Data;
553 }
554 }
555
556 action(f_sendInvToSharers, "f", desc="invalidate sharers for L2 replacement") {
557 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
558 assert(is_valid(cache_entry));
559 out_msg.addr := address;
560 out_msg.Type := CoherenceRequestType:INV;
561 out_msg.Requestor := machineID;
562 out_msg.Destination := cache_entry.Sharers;
563 out_msg.MessageSize := MessageSizeType:Request_Control;
564 }
565 }
566
567 action(fw_sendFwdInvToSharers, "fw", desc="invalidate sharers for request") {
568 peek(L1RequestL2Network_in, RequestMsg) {
569 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
570 assert(is_valid(cache_entry));
571 out_msg.addr := address;
572 out_msg.Type := CoherenceRequestType:INV;
573 out_msg.Requestor := in_msg.Requestor;
574 out_msg.Destination := cache_entry.Sharers;
575 out_msg.MessageSize := MessageSizeType:Request_Control;
576 }
577 }
578 }
579
580 action(fwm_sendFwdInvToSharersMinusRequestor, "fwm", desc="invalidate sharers for request, requestor is sharer") {
581 peek(L1RequestL2Network_in, RequestMsg) {
582 enqueue(L1RequestL2Network_out, RequestMsg, to_l1_latency) {
583 assert(is_valid(cache_entry));
584 out_msg.addr := address;
585 out_msg.Type := CoherenceRequestType:INV;
586 out_msg.Requestor := in_msg.Requestor;
587 out_msg.Destination := cache_entry.Sharers;
588 out_msg.Destination.remove(in_msg.Requestor);
589 out_msg.MessageSize := MessageSizeType:Request_Control;
590 }
591 }
592 }
593
594 // OTHER ACTIONS
595 action(i_allocateTBE, "i", desc="Allocate TBE for request") {
596 check_allocate(TBEs);
597 assert(is_valid(cache_entry));
598 TBEs.allocate(address);
599 set_tbe(TBEs[address]);
600 tbe.L1_GetS_IDs.clear();
601 tbe.DataBlk := cache_entry.DataBlk;
602 tbe.Dirty := cache_entry.Dirty;
603 tbe.pendingAcks := cache_entry.Sharers.count();
604 }
605
606 action(s_deallocateTBE, "s", desc="Deallocate external TBE") {
607 TBEs.deallocate(address);
608 unset_tbe();
609 }
610
611 action(jj_popL1RequestQueue, "\j", desc="Pop incoming L1 request queue") {
612 Tick delay := L1RequestL2Network_in.dequeue(clockEdge());
613 profileMsgDelay(0, ticksToCycles(delay));
614 }
615
616 action(k_popUnblockQueue, "k", desc="Pop incoming unblock queue") {
617 Tick delay := L1unblockNetwork_in.dequeue(clockEdge());
618 profileMsgDelay(0, ticksToCycles(delay));
619 }
620
621 action(o_popIncomingResponseQueue, "o", desc="Pop Incoming Response queue") {
622 Tick delay := responseL2Network_in.dequeue(clockEdge());
623 profileMsgDelay(1, ticksToCycles(delay));
624 }
625
626 action(m_writeDataToCache, "m", desc="Write data from response queue to cache") {
627 peek(responseL2Network_in, ResponseMsg) {
628 assert(is_valid(cache_entry));
629 cache_entry.DataBlk := in_msg.DataBlk;
630 if (in_msg.Dirty) {
631 cache_entry.Dirty := in_msg.Dirty;
632 }
633 }
634 }
635
636 action(mr_writeDataToCacheFromRequest, "mr", desc="Write data from response queue to cache") {
637 peek(L1RequestL2Network_in, RequestMsg) {
638 assert(is_valid(cache_entry));
639 if (in_msg.Dirty) {
640 cache_entry.DataBlk := in_msg.DataBlk;
641 cache_entry.Dirty := in_msg.Dirty;
642 }
643 }
644 }
645
646 action(q_updateAck, "q", desc="update pending ack count") {
647 peek(responseL2Network_in, ResponseMsg) {
648 assert(is_valid(tbe));
649 tbe.pendingAcks := tbe.pendingAcks - in_msg.AckCount;
650 APPEND_TRANSITION_COMMENT(in_msg.AckCount);
651 APPEND_TRANSITION_COMMENT(" p: ");
652 APPEND_TRANSITION_COMMENT(tbe.pendingAcks);
653 }
654 }
655
656 action(qq_writeDataToTBE, "\qq", desc="Write data from response queue to TBE") {
657 peek(responseL2Network_in, ResponseMsg) {
658 assert(is_valid(tbe));
659 tbe.DataBlk := in_msg.DataBlk;
660 tbe.Dirty := in_msg.Dirty;
661 }
662 }
663
664 action(ss_recordGetSL1ID, "\s", desc="Record L1 GetS for load response") {
665 peek(L1RequestL2Network_in, RequestMsg) {
666 assert(is_valid(tbe));
667 tbe.L1_GetS_IDs.add(in_msg.Requestor);
668 }
669 }
670
671 action(xx_recordGetXL1ID, "\x", desc="Record L1 GetX for store response") {
672 peek(L1RequestL2Network_in, RequestMsg) {
673 assert(is_valid(tbe));
674 tbe.L1_GetX_ID := in_msg.Requestor;
675 }
676 }
677
678 action(set_setMRU, "\set", desc="set the MRU entry") {
679 L2cache.setMRU(address);
680 }
681
682 action(qq_allocateL2CacheBlock, "\q", desc="Set L2 cache tag equal to tag of block B.") {
683 if (is_invalid(cache_entry)) {
684 set_cache_entry(L2cache.allocate(address, new Entry));
685 }
686 }
687
688 action(rr_deallocateL2CacheBlock, "\r", desc="Deallocate L2 cache block. Sets the cache to not present, allowing a replacement in parallel with a fetch.") {
689 L2cache.deallocate(address);
690 unset_cache_entry();
691 }
692
693 action(t_sendWBAck, "t", desc="Send writeback ACK") {
694 peek(L1RequestL2Network_in, RequestMsg) {
695 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
696 out_msg.addr := address;
697 out_msg.Type := CoherenceResponseType:WB_ACK;
698 out_msg.Sender := machineID;
699 out_msg.Destination.add(in_msg.Requestor);
700 out_msg.MessageSize := MessageSizeType:Response_Control;
701 }
702 }
703 }
704
705 action(ts_sendInvAckToUpgrader, "ts", desc="Send ACK to upgrader") {
706 peek(L1RequestL2Network_in, RequestMsg) {
707 enqueue(responseL2Network_out, ResponseMsg, to_l1_latency) {
708 assert(is_valid(cache_entry));
709 out_msg.addr := address;
710 out_msg.Type := CoherenceResponseType:ACK;
711 out_msg.Sender := machineID;
712 out_msg.Destination.add(in_msg.Requestor);
713 out_msg.MessageSize := MessageSizeType:Response_Control;
714 // upgrader doesn't get ack from itself, hence the + 1
715 out_msg.AckCount := 0 - cache_entry.Sharers.count() + 1;
716 }
717 }
718 }
719
720 action(uu_profileMiss, "\um", desc="Profile the demand miss") {
721 ++L2cache.demand_misses;
722 }
723
724 action(uu_profileHit, "\uh", desc="Profile the demand hit") {
725 ++L2cache.demand_hits;
726 }
727
728 action(nn_addSharer, "\n", desc="Add L1 sharer to list") {
729 peek(L1RequestL2Network_in, RequestMsg) {
730 assert(is_valid(cache_entry));
731 addSharer(address, in_msg.Requestor, cache_entry);
732 APPEND_TRANSITION_COMMENT( cache_entry.Sharers );
733 }
734 }
735
736 action(nnu_addSharerFromUnblock, "\nu", desc="Add L1 sharer to list") {
737 peek(L1unblockNetwork_in, ResponseMsg) {
738 assert(is_valid(cache_entry));
739 addSharer(address, in_msg.Sender, cache_entry);
740 }
741 }
742
743 action(kk_removeRequestSharer, "\k", desc="Remove L1 Request sharer from list") {
744 peek(L1RequestL2Network_in, RequestMsg) {
745 assert(is_valid(cache_entry));
746 cache_entry.Sharers.remove(in_msg.Requestor);
747 }
748 }
749
750 action(ll_clearSharers, "\l", desc="Remove all L1 sharers from list") {
751 peek(L1RequestL2Network_in, RequestMsg) {
752 assert(is_valid(cache_entry));
753 cache_entry.Sharers.clear();
754 }
755 }
756
757 action(mm_markExclusive, "\m", desc="set the exclusive owner") {
758 peek(L1RequestL2Network_in, RequestMsg) {
759 assert(is_valid(cache_entry));
760 cache_entry.Sharers.clear();
761 cache_entry.Exclusive := in_msg.Requestor;
762 addSharer(address, in_msg.Requestor, cache_entry);
763 }
764 }
765
766 action(mmu_markExclusiveFromUnblock, "\mu", desc="set the exclusive owner") {
767 peek(L1unblockNetwork_in, ResponseMsg) {
768 assert(is_valid(cache_entry));
769 cache_entry.Sharers.clear();
770 cache_entry.Exclusive := in_msg.Sender;
771 addSharer(address, in_msg.Sender, cache_entry);
772 }
773 }
774
775 action(zz_stallAndWaitL1RequestQueue, "zz", desc="recycle L1 request queue") {
776 stall_and_wait(L1RequestL2Network_in, address);
777 }
778
779 action(zn_recycleResponseNetwork, "zn", desc="recycle memory request") {
780 responseL2Network_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
781 }
782
783 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
784 wakeUpBuffers(address);
785 }
786
787 //*****************************************************
788 // TRANSITIONS
789 //*****************************************************
790
791
792 //===============================================
793 // BASE STATE - I
794
795 // Transitions from I (Idle)
796 transition({NP, IS, ISS, IM, SS, M, M_I, I_I, S_I, MT_IB, MT_SB}, L1_PUTX) {
797 t_sendWBAck;
798 jj_popL1RequestQueue;
799 }
800
801 transition({NP, SS, M, MT, M_I, I_I, S_I, IS, ISS, IM, MT_IB, MT_SB}, L1_PUTX_old) {
802 t_sendWBAck;
803 jj_popL1RequestQueue;
804 }
805
806 transition({IM, IS, ISS, SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L2_Replacement, L2_Replacement_clean}) {
807 zz_stallAndWaitL1RequestQueue;
808 }
809
810 transition({IM, IS, ISS, SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, MEM_Inv) {
811 zn_recycleResponseNetwork;
812 }
813
814 transition({I_I, S_I, M_I, MT_I, MCT_I, NP}, MEM_Inv) {
815 o_popIncomingResponseQueue;
816 }
817
818
819 transition({SS_MB, MT_MB, MT_IIB, MT_IB, MT_SB}, {L1_GETS, L1_GET_INSTR, L1_GETX, L1_UPGRADE}) {
820 zz_stallAndWaitL1RequestQueue;
821 }
822
823
824 transition(NP, L1_GETS, ISS) {
825 qq_allocateL2CacheBlock;
826 ll_clearSharers;
827 nn_addSharer;
828 i_allocateTBE;
829 ss_recordGetSL1ID;
830 a_issueFetchToMemory;
831 uu_profileMiss;
832 jj_popL1RequestQueue;
833 }
834
835 transition(NP, L1_GET_INSTR, IS) {
836 qq_allocateL2CacheBlock;
837 ll_clearSharers;
838 nn_addSharer;
839 i_allocateTBE;
840 ss_recordGetSL1ID;
841 a_issueFetchToMemory;
842 uu_profileMiss;
843 jj_popL1RequestQueue;
844 }
845
846 transition(NP, L1_GETX, IM) {
847 qq_allocateL2CacheBlock;
848 ll_clearSharers;
849 // nn_addSharer;
850 i_allocateTBE;
851 xx_recordGetXL1ID;
852 a_issueFetchToMemory;
853 uu_profileMiss;
854 jj_popL1RequestQueue;
855 }
856
857
858 // transitions from IS/IM
859
860 transition(ISS, Mem_Data, MT_MB) {
861 m_writeDataToCache;
862 ex_sendExclusiveDataToGetSRequestors;
863 s_deallocateTBE;
864 o_popIncomingResponseQueue;
865 }
866
867 transition(IS, Mem_Data, SS) {
868 m_writeDataToCache;
869 e_sendDataToGetSRequestors;
870 s_deallocateTBE;
871 o_popIncomingResponseQueue;
872 kd_wakeUpDependents;
873 }
874
875 transition(IM, Mem_Data, MT_MB) {
876 m_writeDataToCache;
877 ee_sendDataToGetXRequestor;
878 s_deallocateTBE;
879 o_popIncomingResponseQueue;
880 }
881
882 transition({IS, ISS}, {L1_GETS, L1_GET_INSTR}, IS) {
883 nn_addSharer;
884 ss_recordGetSL1ID;
885 uu_profileMiss;
886 jj_popL1RequestQueue;
887 }
888
889 transition({IS, ISS}, L1_GETX) {
890 zz_stallAndWaitL1RequestQueue;
891 }
892
893 transition(IM, {L1_GETX, L1_GETS, L1_GET_INSTR}) {
894 zz_stallAndWaitL1RequestQueue;
895 }
896
897 // transitions from SS
898 transition(SS, {L1_GETS, L1_GET_INSTR}) {
899 ds_sendSharedDataToRequestor;
900 nn_addSharer;
901 set_setMRU;
902 uu_profileHit;
903 jj_popL1RequestQueue;
904 }
905
906
907 transition(SS, L1_GETX, SS_MB) {
908 d_sendDataToRequestor;
909 // fw_sendFwdInvToSharers;
910 fwm_sendFwdInvToSharersMinusRequestor;
911 set_setMRU;
912 uu_profileHit;
913 jj_popL1RequestQueue;
914 }
915
916 transition(SS, L1_UPGRADE, SS_MB) {
917 fwm_sendFwdInvToSharersMinusRequestor;
918 ts_sendInvAckToUpgrader;
919 set_setMRU;
920 uu_profileHit;
921 jj_popL1RequestQueue;
922 }
923
924 transition(SS, L2_Replacement_clean, I_I) {
925 i_allocateTBE;
926 f_sendInvToSharers;
927 rr_deallocateL2CacheBlock;
928 }
929
930 transition(SS, {L2_Replacement, MEM_Inv}, S_I) {
931 i_allocateTBE;
932 f_sendInvToSharers;
933 rr_deallocateL2CacheBlock;
934 }
935
936
937 transition(M, L1_GETX, MT_MB) {
938 d_sendDataToRequestor;
939 set_setMRU;
940 uu_profileHit;
941 jj_popL1RequestQueue;
942 }
943
944 transition(M, L1_GET_INSTR, SS) {
945 d_sendDataToRequestor;
946 nn_addSharer;
947 set_setMRU;
948 uu_profileHit;
949 jj_popL1RequestQueue;
950 }
951
952 transition(M, L1_GETS, MT_MB) {
953 dd_sendExclusiveDataToRequestor;
954 set_setMRU;
955 uu_profileHit;
956 jj_popL1RequestQueue;
957 }
958
959 transition(M, {L2_Replacement, MEM_Inv}, M_I) {
960 i_allocateTBE;
961 c_exclusiveReplacement;
962 rr_deallocateL2CacheBlock;
963 }
964
965 transition(M, L2_Replacement_clean, M_I) {
966 i_allocateTBE;
967 c_exclusiveCleanReplacement;
968 rr_deallocateL2CacheBlock;
969 }
970
971
972 // transitions from MT
973
974 transition(MT, L1_GETX, MT_MB) {
975 b_forwardRequestToExclusive;
976 uu_profileMiss;
977 set_setMRU;
978 jj_popL1RequestQueue;
979 }
980
981
982 transition(MT, {L1_GETS, L1_GET_INSTR}, MT_IIB) {
983 b_forwardRequestToExclusive;
984 uu_profileMiss;
985 set_setMRU;
986 jj_popL1RequestQueue;
987 }
988
989 transition(MT, {L2_Replacement, MEM_Inv}, MT_I) {
990 i_allocateTBE;
991 f_sendInvToSharers;
992 rr_deallocateL2CacheBlock;
993 }
994
995 transition(MT, L2_Replacement_clean, MCT_I) {
996 i_allocateTBE;
997 f_sendInvToSharers;
998 rr_deallocateL2CacheBlock;
999 }
1000
1001 transition(MT, L1_PUTX, M) {
1002 ll_clearSharers;
1003 mr_writeDataToCacheFromRequest;
1004 t_sendWBAck;
1005 jj_popL1RequestQueue;
1006 }
1007
1008 transition({SS_MB,MT_MB}, Exclusive_Unblock, MT) {
1009 // update actual directory
1010 mmu_markExclusiveFromUnblock;
1011 k_popUnblockQueue;
1012 kd_wakeUpDependents;
1013 }
1014
1015 transition(MT_IIB, {L1_PUTX, L1_PUTX_old}){
1016 zz_stallAndWaitL1RequestQueue;
1017 }
1018
1019 transition(MT_IIB, Unblock, MT_IB) {
1020 nnu_addSharerFromUnblock;
1021 k_popUnblockQueue;
1022 }
1023
1024 transition(MT_IIB, {WB_Data, WB_Data_clean}, MT_SB) {
1025 m_writeDataToCache;
1026 o_popIncomingResponseQueue;
1027 }
1028
1029 transition(MT_IB, {WB_Data, WB_Data_clean}, SS) {
1030 m_writeDataToCache;
1031 o_popIncomingResponseQueue;
1032 kd_wakeUpDependents;
1033 }
1034
1035 transition(MT_SB, Unblock, SS) {
1036 nnu_addSharerFromUnblock;
1037 k_popUnblockQueue;
1038 kd_wakeUpDependents;
1039 }
1040
1041 // writeback states
1042 transition({I_I, S_I, MT_I, MCT_I, M_I}, {L1_GETX, L1_UPGRADE, L1_GETS, L1_GET_INSTR}) {
1043 zz_stallAndWaitL1RequestQueue;
1044 }
1045
1046 transition(I_I, Ack) {
1047 q_updateAck;
1048 o_popIncomingResponseQueue;
1049 }
1050
1051 transition(I_I, Ack_all, M_I) {
1052 c_exclusiveCleanReplacement;
1053 o_popIncomingResponseQueue;
1054 }
1055
1056 transition({MT_I, MCT_I}, WB_Data, M_I) {
1057 qq_writeDataToTBE;
1058 ct_exclusiveReplacementFromTBE;
1059 o_popIncomingResponseQueue;
1060 }
1061
1062 transition(MCT_I, {WB_Data_clean, Ack_all}, M_I) {
1063 c_exclusiveCleanReplacement;
1064 o_popIncomingResponseQueue;
1065 }
1066
1067 transition(MCT_I, {L1_PUTX, L1_PUTX_old}){
1068 zz_stallAndWaitL1RequestQueue;
1069 }
1070
1071 // L1 never changed Dirty data
1072 transition(MT_I, {WB_Data_clean, Ack_all}, M_I) {
1073 ct_exclusiveReplacementFromTBE;
1074 o_popIncomingResponseQueue;
1075 }
1076
1077 transition(MT_I, {L1_PUTX, L1_PUTX_old}){
1078 zz_stallAndWaitL1RequestQueue;
1079 }
1080
1081 // possible race between unblock and immediate replacement
1082 transition({MT_MB,SS_MB}, {L1_PUTX, L1_PUTX_old}) {
1083 zz_stallAndWaitL1RequestQueue;
1084 }
1085
1086 transition(S_I, Ack) {
1087 q_updateAck;
1088 o_popIncomingResponseQueue;
1089 }
1090
1091 transition(S_I, Ack_all, M_I) {
1092 ct_exclusiveReplacementFromTBE;
1093 o_popIncomingResponseQueue;
1094 }
1095
1096 transition(M_I, Mem_Ack, NP) {
1097 s_deallocateTBE;
1098 o_popIncomingResponseQueue;
1099 kd_wakeUpDependents;
1100 }
1101}