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