mem-cache: Add match functions to QueueEntry
[gem5.git] / src / mem / protocol / MESI_Two_Level-dir.sm
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
29 machine(MachineType:Directory, "MESI Two Level directory protocol")
30 : DirectoryMemory * directory;
31 Cycles to_mem_ctrl_latency := 1;
32 Cycles directory_latency := 6;
33
34 MessageBuffer * requestToDir, network="From", virtual_network="0",
35 vnet_type="request";
36 MessageBuffer * responseToDir, network="From", virtual_network="1",
37 vnet_type="response";
38 MessageBuffer * responseFromDir, network="To", virtual_network="1",
39 vnet_type="response";
40
41 MessageBuffer * responseFromMemory;
42 {
43 // STATES
44 state_declaration(State, desc="Directory states", default="Directory_State_I") {
45 // Base states
46 I, AccessPermission:Read_Write, desc="dir is the owner and memory is up-to-date, all other copies are Invalid";
47 ID, AccessPermission:Busy, desc="Intermediate state for DMA_READ when in I";
48 ID_W, AccessPermission:Busy, desc="Intermediate state for DMA_WRITE when in I";
49
50 M, AccessPermission:Maybe_Stale, desc="memory copy may be stale, i.e. other modified copies may exist";
51 IM, AccessPermission:Busy, desc="Intermediate State I>M";
52 MI, AccessPermission:Busy, desc="Intermediate State M>I";
53 M_DRD, AccessPermission:Busy, desc="Intermediate State when there is a dma read";
54 M_DRDI, AccessPermission:Busy, desc="Intermediate State when there is a dma read";
55 M_DWR, AccessPermission:Busy, desc="Intermediate State when there is a dma write";
56 M_DWRI, AccessPermission:Busy, desc="Intermediate State when there is a dma write";
57 }
58
59 // Events
60 enumeration(Event, desc="Directory events") {
61 Fetch, desc="A memory fetch arrives";
62 Data, desc="writeback data arrives";
63 Memory_Data, desc="Fetched data from memory arrives";
64 Memory_Ack, desc="Writeback Ack from memory arrives";
65 //added by SS for dma
66 DMA_READ, desc="A DMA Read memory request";
67 DMA_WRITE, desc="A DMA Write memory request";
68 CleanReplacement, desc="Clean Replacement in L2 cache";
69
70 }
71
72 // TYPES
73
74 // DirectoryEntry
75 structure(Entry, desc="...", interface="AbstractEntry") {
76 State DirectoryState, desc="Directory state";
77 MachineID Owner;
78 }
79
80 // TBE entries for DMA requests
81 structure(TBE, desc="TBE entries for outstanding DMA requests") {
82 Addr PhysicalAddress, desc="physical address";
83 State TBEState, desc="Transient State";
84 DataBlock DataBlk, desc="Data to be written (DMA write only)";
85 int Len, desc="...";
86 MachineID Requestor, desc="The DMA engine that sent the request";
87 }
88
89 structure(TBETable, external="yes") {
90 TBE lookup(Addr);
91 void allocate(Addr);
92 void deallocate(Addr);
93 bool isPresent(Addr);
94 bool functionalRead(Packet *pkt);
95 int functionalWrite(Packet *pkt);
96 }
97
98
99 // ** OBJECTS **
100 TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
101
102 Tick clockEdge();
103 Tick cyclesToTicks(Cycles c);
104 void set_tbe(TBE tbe);
105 void unset_tbe();
106 void wakeUpBuffers(Addr a);
107
108 Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
109 Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
110
111 if (is_valid(dir_entry)) {
112 return dir_entry;
113 }
114
115 dir_entry := static_cast(Entry, "pointer",
116 directory.allocate(addr, new Entry));
117 return dir_entry;
118 }
119
120 State getState(TBE tbe, Addr addr) {
121 if (is_valid(tbe)) {
122 return tbe.TBEState;
123 } else if (directory.isPresent(addr)) {
124 return getDirectoryEntry(addr).DirectoryState;
125 } else {
126 return State:I;
127 }
128 }
129
130 void setState(TBE tbe, Addr addr, State state) {
131 if (is_valid(tbe)) {
132 tbe.TBEState := state;
133 }
134
135 if (directory.isPresent(addr)) {
136 getDirectoryEntry(addr).DirectoryState := state;
137 }
138 }
139
140 AccessPermission getAccessPermission(Addr addr) {
141 TBE tbe := TBEs[addr];
142 if(is_valid(tbe)) {
143 DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(tbe.TBEState));
144 return Directory_State_to_permission(tbe.TBEState);
145 }
146
147 if(directory.isPresent(addr)) {
148 DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState));
149 return Directory_State_to_permission(getDirectoryEntry(addr).DirectoryState);
150 }
151
152 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
153 return AccessPermission:NotPresent;
154 }
155
156 void functionalRead(Addr addr, Packet *pkt) {
157 TBE tbe := TBEs[addr];
158 if(is_valid(tbe)) {
159 testAndRead(addr, tbe.DataBlk, pkt);
160 } else {
161 functionalMemoryRead(pkt);
162 }
163 }
164
165 int functionalWrite(Addr addr, Packet *pkt) {
166 int num_functional_writes := 0;
167
168 TBE tbe := TBEs[addr];
169 if(is_valid(tbe)) {
170 num_functional_writes := num_functional_writes +
171 testAndWrite(addr, tbe.DataBlk, pkt);
172 }
173
174 num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
175 return num_functional_writes;
176 }
177
178 void setAccessPermission(Addr addr, State state) {
179 if (directory.isPresent(addr)) {
180 getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
181 }
182 }
183
184 bool isGETRequest(CoherenceRequestType type) {
185 return (type == CoherenceRequestType:GETS) ||
186 (type == CoherenceRequestType:GET_INSTR) ||
187 (type == CoherenceRequestType:GETX);
188 }
189
190 // ** OUT_PORTS **
191 out_port(responseNetwork_out, ResponseMsg, responseFromDir);
192
193 // ** IN_PORTS **
194
195 in_port(requestNetwork_in, RequestMsg, requestToDir, rank = 0) {
196 if (requestNetwork_in.isReady(clockEdge())) {
197 peek(requestNetwork_in, RequestMsg) {
198 assert(in_msg.Destination.isElement(machineID));
199 if (isGETRequest(in_msg.Type)) {
200 trigger(Event:Fetch, in_msg.addr, TBEs[in_msg.addr]);
201 } else if (in_msg.Type == CoherenceRequestType:DMA_READ) {
202 trigger(Event:DMA_READ, makeLineAddress(in_msg.addr),
203 TBEs[makeLineAddress(in_msg.addr)]);
204 } else if (in_msg.Type == CoherenceRequestType:DMA_WRITE) {
205 trigger(Event:DMA_WRITE, makeLineAddress(in_msg.addr),
206 TBEs[makeLineAddress(in_msg.addr)]);
207 } else {
208 DPRINTF(RubySlicc, "%s\n", in_msg);
209 error("Invalid message");
210 }
211 }
212 }
213 }
214
215 in_port(responseNetwork_in, ResponseMsg, responseToDir, rank = 1) {
216 if (responseNetwork_in.isReady(clockEdge())) {
217 peek(responseNetwork_in, ResponseMsg) {
218 assert(in_msg.Destination.isElement(machineID));
219 if (in_msg.Type == CoherenceResponseType:MEMORY_DATA) {
220 trigger(Event:Data, in_msg.addr, TBEs[in_msg.addr]);
221 } else if (in_msg.Type == CoherenceResponseType:ACK) {
222 trigger(Event:CleanReplacement, in_msg.addr, TBEs[in_msg.addr]);
223 } else {
224 DPRINTF(RubySlicc, "%s\n", in_msg.Type);
225 error("Invalid message");
226 }
227 }
228 }
229 }
230
231 // off-chip memory request/response is done
232 in_port(memQueue_in, MemoryMsg, responseFromMemory, rank = 2) {
233 if (memQueue_in.isReady(clockEdge())) {
234 peek(memQueue_in, MemoryMsg) {
235 if (in_msg.Type == MemoryRequestType:MEMORY_READ) {
236 trigger(Event:Memory_Data, in_msg.addr, TBEs[in_msg.addr]);
237 } else if (in_msg.Type == MemoryRequestType:MEMORY_WB) {
238 trigger(Event:Memory_Ack, in_msg.addr, TBEs[in_msg.addr]);
239 } else {
240 DPRINTF(RubySlicc, "%s\n", in_msg.Type);
241 error("Invalid message");
242 }
243 }
244 }
245 }
246
247
248 // Actions
249 action(a_sendAck, "a", desc="Send ack to L2") {
250 peek(responseNetwork_in, ResponseMsg) {
251 enqueue(responseNetwork_out, ResponseMsg, to_mem_ctrl_latency) {
252 out_msg.addr := address;
253 out_msg.Type := CoherenceResponseType:MEMORY_ACK;
254 out_msg.Sender := machineID;
255 out_msg.Destination.add(in_msg.Sender);
256 out_msg.MessageSize := MessageSizeType:Response_Control;
257 }
258 }
259 }
260
261 action(d_sendData, "d", desc="Send data to requestor") {
262 peek(memQueue_in, MemoryMsg) {
263 enqueue(responseNetwork_out, ResponseMsg, to_mem_ctrl_latency) {
264 out_msg.addr := address;
265 out_msg.Type := CoherenceResponseType:MEMORY_DATA;
266 out_msg.Sender := machineID;
267 out_msg.Destination.add(in_msg.OriginalRequestorMachId);
268 out_msg.DataBlk := in_msg.DataBlk;
269 out_msg.Dirty := false;
270 out_msg.MessageSize := MessageSizeType:Response_Data;
271
272 Entry e := getDirectoryEntry(in_msg.addr);
273 e.Owner := in_msg.OriginalRequestorMachId;
274 }
275 }
276 }
277
278 // Actions
279 action(aa_sendAck, "aa", desc="Send ack to L2") {
280 peek(memQueue_in, MemoryMsg) {
281 enqueue(responseNetwork_out, ResponseMsg, to_mem_ctrl_latency) {
282 out_msg.addr := address;
283 out_msg.Type := CoherenceResponseType:MEMORY_ACK;
284 out_msg.Sender := machineID;
285 out_msg.Destination.add(in_msg.OriginalRequestorMachId);
286 out_msg.MessageSize := MessageSizeType:Response_Control;
287 }
288 }
289 }
290
291 action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
292 requestNetwork_in.dequeue(clockEdge());
293 }
294
295 action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
296 responseNetwork_in.dequeue(clockEdge());
297 }
298
299 action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
300 memQueue_in.dequeue(clockEdge());
301 }
302
303 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
304 wakeUpBuffers(address);
305 }
306
307 action(qf_queueMemoryFetchRequest, "qf", desc="Queue off-chip fetch request") {
308 peek(requestNetwork_in, RequestMsg) {
309 queueMemoryRead(in_msg.Requestor, address, to_mem_ctrl_latency);
310 }
311 }
312
313 action(qw_queueMemoryWBRequest, "qw", desc="Queue off-chip writeback request") {
314 peek(responseNetwork_in, ResponseMsg) {
315 queueMemoryWrite(in_msg.Sender, address, to_mem_ctrl_latency,
316 in_msg.DataBlk);
317 }
318 }
319
320 //added by SS for dma
321 action(qf_queueMemoryFetchRequestDMA, "qfd", desc="Queue off-chip fetch request") {
322 peek(requestNetwork_in, RequestMsg) {
323 queueMemoryRead(in_msg.Requestor, address, to_mem_ctrl_latency);
324 }
325 }
326
327 action(p_popIncomingDMARequestQueue, "p", desc="Pop incoming DMA queue") {
328 requestNetwork_in.dequeue(clockEdge());
329 }
330
331 action(dr_sendDMAData, "dr", desc="Send Data to DMA controller from directory") {
332 peek(memQueue_in, MemoryMsg) {
333 enqueue(responseNetwork_out, ResponseMsg, to_mem_ctrl_latency) {
334 assert(is_valid(tbe));
335 out_msg.addr := address;
336 out_msg.Type := CoherenceResponseType:DATA;
337 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
338 out_msg.Destination.add(tbe.Requestor);
339 out_msg.MessageSize := MessageSizeType:Response_Data;
340 }
341 }
342 }
343
344 action(qw_queueMemoryWBRequest_partial, "qwp",
345 desc="Queue off-chip writeback request") {
346 peek(requestNetwork_in, RequestMsg) {
347 queueMemoryWritePartial(machineID, address, to_mem_ctrl_latency,
348 in_msg.DataBlk, in_msg.Len);
349 }
350 }
351
352 action(da_sendDMAAck, "da", desc="Send Ack to DMA controller") {
353 enqueue(responseNetwork_out, ResponseMsg, to_mem_ctrl_latency) {
354 assert(is_valid(tbe));
355 out_msg.addr := address;
356 out_msg.Type := CoherenceResponseType:ACK;
357 out_msg.Destination.add(tbe.Requestor);
358 out_msg.MessageSize := MessageSizeType:Writeback_Control;
359 }
360 }
361
362 action(z_stallAndWaitRequest, "z", desc="recycle request queue") {
363 stall_and_wait(requestNetwork_in, address);
364 }
365
366 action(zz_recycleDMAQueue, "zz", desc="recycle DMA queue") {
367 requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
368 }
369
370 action(inv_sendCacheInvalidate, "inv", desc="Invalidate a cache block") {
371 peek(requestNetwork_in, RequestMsg) {
372 enqueue(responseNetwork_out, ResponseMsg, directory_latency) {
373 out_msg.addr := address;
374 out_msg.Type := CoherenceResponseType:INV;
375 out_msg.Sender := machineID;
376 out_msg.Destination.add(getDirectoryEntry(address).Owner);
377 out_msg.MessageSize := MessageSizeType:Response_Control;
378 }
379 }
380 }
381
382
383 action(drp_sendDMAData, "drp", desc="Send Data to DMA controller from incoming PUTX") {
384 peek(responseNetwork_in, ResponseMsg) {
385 enqueue(responseNetwork_out, ResponseMsg, to_mem_ctrl_latency) {
386 assert(is_valid(tbe));
387 out_msg.addr := address;
388 out_msg.Type := CoherenceResponseType:DATA;
389 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
390 out_msg.Destination.add(tbe.Requestor);
391 out_msg.MessageSize := MessageSizeType:Response_Data;
392 }
393 }
394 }
395
396 action(v_allocateTBE, "v", desc="Allocate TBE") {
397 peek(requestNetwork_in, RequestMsg) {
398 TBEs.allocate(address);
399 set_tbe(TBEs[address]);
400 tbe.DataBlk := in_msg.DataBlk;
401 tbe.PhysicalAddress := in_msg.addr;
402 tbe.Len := in_msg.Len;
403 tbe.Requestor := in_msg.Requestor;
404 }
405 }
406
407 action(qw_queueMemoryWBRequest_partialTBE, "qwt",
408 desc="Queue off-chip writeback request") {
409 peek(responseNetwork_in, ResponseMsg) {
410 queueMemoryWritePartial(in_msg.Sender, tbe.PhysicalAddress,
411 to_mem_ctrl_latency, tbe.DataBlk, tbe.Len);
412 }
413 }
414
415 action(w_deallocateTBE, "w", desc="Deallocate TBE") {
416 TBEs.deallocate(address);
417 unset_tbe();
418 }
419
420
421 // TRANSITIONS
422
423 transition(I, Fetch, IM) {
424 qf_queueMemoryFetchRequest;
425 j_popIncomingRequestQueue;
426 }
427
428 transition(M, Fetch) {
429 inv_sendCacheInvalidate;
430 z_stallAndWaitRequest;
431 }
432
433 transition(IM, Memory_Data, M) {
434 d_sendData;
435 l_popMemQueue;
436 kd_wakeUpDependents;
437 }
438 //added by SS
439 transition(M, CleanReplacement, I) {
440 a_sendAck;
441 k_popIncomingResponseQueue;
442 kd_wakeUpDependents;
443 }
444
445 transition(M, Data, MI) {
446 qw_queueMemoryWBRequest;
447 k_popIncomingResponseQueue;
448 }
449
450 transition(MI, Memory_Ack, I) {
451 aa_sendAck;
452 l_popMemQueue;
453 kd_wakeUpDependents;
454 }
455
456
457 //added by SS for dma support
458 transition(I, DMA_READ, ID) {
459 v_allocateTBE;
460 qf_queueMemoryFetchRequestDMA;
461 j_popIncomingRequestQueue;
462 }
463
464 transition(ID, Memory_Data, I) {
465 dr_sendDMAData;
466 w_deallocateTBE;
467 l_popMemQueue;
468 kd_wakeUpDependents;
469 }
470
471 transition(I, DMA_WRITE, ID_W) {
472 v_allocateTBE;
473 qw_queueMemoryWBRequest_partial;
474 j_popIncomingRequestQueue;
475 }
476
477 transition(ID_W, Memory_Ack, I) {
478 da_sendDMAAck;
479 w_deallocateTBE;
480 l_popMemQueue;
481 kd_wakeUpDependents;
482 }
483
484 transition({ID, ID_W, M_DRDI, M_DWRI, IM, MI}, {Fetch, Data} ) {
485 z_stallAndWaitRequest;
486 }
487
488 transition({ID, ID_W, M_DRD, M_DRDI, M_DWR, M_DWRI, IM, MI}, {DMA_WRITE, DMA_READ} ) {
489 zz_recycleDMAQueue;
490 }
491
492
493 transition(M, DMA_READ, M_DRD) {
494 v_allocateTBE;
495 inv_sendCacheInvalidate;
496 j_popIncomingRequestQueue;
497 }
498
499 transition(M_DRD, Data, M_DRDI) {
500 drp_sendDMAData;
501 w_deallocateTBE;
502 qw_queueMemoryWBRequest;
503 k_popIncomingResponseQueue;
504 }
505
506 transition(M_DRDI, Memory_Ack, I) {
507 aa_sendAck;
508 l_popMemQueue;
509 kd_wakeUpDependents;
510 }
511
512 transition(M, DMA_WRITE, M_DWR) {
513 v_allocateTBE;
514 inv_sendCacheInvalidate;
515 j_popIncomingRequestQueue;
516 }
517
518 transition(M_DWR, Data, M_DWRI) {
519 qw_queueMemoryWBRequest_partialTBE;
520 k_popIncomingResponseQueue;
521 }
522
523 transition(M_DWRI, Memory_Ack, I) {
524 aa_sendAck;
525 da_sendDMAAck;
526 w_deallocateTBE;
527 l_popMemQueue;
528 kd_wakeUpDependents;
529 }
530 }