2 * Copyright (c) 1999-2013 Mark D. Hill and David A. Wood
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.
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.
29 machine(Directory, "MESI Two Level directory protocol")
30 : DirectoryMemory * directory;
31 Cycles to_mem_ctrl_latency := 1;
32 Cycles directory_latency := 6;
34 MessageBuffer * requestToDir, network="From", virtual_network="0",
36 MessageBuffer * responseToDir, network="From", virtual_network="1",
38 MessageBuffer * responseFromDir, network="To", virtual_network="1",
41 MessageBuffer * responseFromMemory;
44 state_declaration(State, desc="Directory states", default="Directory_State_I") {
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";
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";
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";
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";
75 structure(Entry, desc="...", interface="AbstractEntry") {
76 State DirectoryState, desc="Directory state";
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)";
88 structure(TBETable, external="yes") {
91 void deallocate(Addr);
93 bool functionalRead(Packet *pkt);
94 int functionalWrite(Packet *pkt);
99 TBETable TBEs, template="<Directory_TBE>", constructor="m_number_of_TBEs";
102 Tick cyclesToTicks(Cycles c);
103 void set_tbe(TBE tbe);
105 void wakeUpBuffers(Addr a);
107 Entry getDirectoryEntry(Addr addr), return_by_pointer="yes" {
108 Entry dir_entry := static_cast(Entry, "pointer", directory[addr]);
110 if (is_valid(dir_entry)) {
114 dir_entry := static_cast(Entry, "pointer",
115 directory.allocate(addr, new Entry));
119 State getState(TBE tbe, Addr addr) {
122 } else if (directory.isPresent(addr)) {
123 return getDirectoryEntry(addr).DirectoryState;
129 void setState(TBE tbe, Addr addr, State state) {
131 tbe.TBEState := state;
134 if (directory.isPresent(addr)) {
135 getDirectoryEntry(addr).DirectoryState := state;
139 AccessPermission getAccessPermission(Addr addr) {
140 TBE tbe := TBEs[addr];
142 DPRINTF(RubySlicc, "%s\n", Directory_State_to_permission(tbe.TBEState));
143 return Directory_State_to_permission(tbe.TBEState);
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);
151 DPRINTF(RubySlicc, "%s\n", AccessPermission:NotPresent);
152 return AccessPermission:NotPresent;
155 void functionalRead(Addr addr, Packet *pkt) {
156 TBE tbe := TBEs[addr];
158 testAndRead(addr, tbe.DataBlk, pkt);
160 functionalMemoryRead(pkt);
164 int functionalWrite(Addr addr, Packet *pkt) {
165 int num_functional_writes := 0;
167 TBE tbe := TBEs[addr];
169 num_functional_writes := num_functional_writes +
170 testAndWrite(addr, tbe.DataBlk, pkt);
173 num_functional_writes := num_functional_writes + functionalMemoryWrite(pkt);
174 return num_functional_writes;
177 void setAccessPermission(Addr addr, State state) {
178 if (directory.isPresent(addr)) {
179 getDirectoryEntry(addr).changePermission(Directory_State_to_permission(state));
183 bool isGETRequest(CoherenceRequestType type) {
184 return (type == CoherenceRequestType:GETS) ||
185 (type == CoherenceRequestType:GET_INSTR) ||
186 (type == CoherenceRequestType:GETX);
190 out_port(responseNetwork_out, ResponseMsg, responseFromDir);
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)]);
207 DPRINTF(RubySlicc, "%s\n", in_msg);
208 error("Invalid message");
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]);
223 DPRINTF(RubySlicc, "%s\n", in_msg.Type);
224 error("Invalid message");
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]);
239 DPRINTF(RubySlicc, "%s\n", in_msg.Type);
240 error("Invalid message");
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;
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;
271 Entry e := getDirectoryEntry(in_msg.addr);
272 e.Owner := in_msg.OriginalRequestorMachId;
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;
290 action(j_popIncomingRequestQueue, "j", desc="Pop incoming request queue") {
291 requestNetwork_in.dequeue(clockEdge());
294 action(k_popIncomingResponseQueue, "k", desc="Pop incoming request queue") {
295 responseNetwork_in.dequeue(clockEdge());
298 action(l_popMemQueue, "q", desc="Pop off-chip request queue") {
299 memQueue_in.dequeue(clockEdge());
302 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") {
303 wakeUpBuffers(address);
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);
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,
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);
326 action(p_popIncomingDMARequestQueue, "p", desc="Pop incoming DMA queue") {
327 requestNetwork_in.dequeue(clockEdge());
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;
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);
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;
359 action(z_stallAndWaitRequest, "z", desc="recycle request queue") {
360 stall_and_wait(requestNetwork_in, address);
363 action(zz_recycleDMAQueue, "zz", desc="recycle DMA queue") {
364 requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency));
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;
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;
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;
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);
410 action(w_deallocateTBE, "w", desc="Deallocate TBE") {
411 TBEs.deallocate(address);
418 transition(I, Fetch, IM) {
419 qf_queueMemoryFetchRequest;
420 j_popIncomingRequestQueue;
423 transition(M, Fetch) {
424 inv_sendCacheInvalidate;
425 z_stallAndWaitRequest;
428 transition(IM, Memory_Data, M) {
434 transition(M, CleanReplacement, I) {
436 k_popIncomingResponseQueue;
440 transition(M, Data, MI) {
441 qw_queueMemoryWBRequest;
442 k_popIncomingResponseQueue;
445 transition(MI, Memory_Ack, I) {
452 //added by SS for dma support
453 transition(I, DMA_READ, ID) {
454 qf_queueMemoryFetchRequestDMA;
455 j_popIncomingRequestQueue;
458 transition(ID, Memory_Data, I) {
464 transition(I, DMA_WRITE, ID_W) {
465 qw_queueMemoryWBRequest_partial;
466 j_popIncomingRequestQueue;
469 transition(ID_W, Memory_Ack, I) {
475 transition({ID, ID_W, M_DRDI, M_DWRI, IM, MI}, {Fetch, Data} ) {
476 z_stallAndWaitRequest;
479 transition({ID, ID_W, M_DRD, M_DRDI, M_DWR, M_DWRI, IM, MI}, {DMA_WRITE, DMA_READ} ) {
484 transition(M, DMA_READ, M_DRD) {
485 inv_sendCacheInvalidate;
486 j_popIncomingRequestQueue;
489 transition(M_DRD, Data, M_DRDI) {
491 qw_queueMemoryWBRequest;
492 k_popIncomingResponseQueue;
495 transition(M_DRDI, Memory_Ack, I) {
501 transition(M, DMA_WRITE, M_DWR) {
503 inv_sendCacheInvalidate;
504 j_popIncomingRequestQueue;
507 transition(M_DWR, Data, M_DWRI) {
508 qw_queueMemoryWBRequest_partialTBE;
509 k_popIncomingResponseQueue;
512 transition(M_DWRI, Memory_Ack, I) {