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: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} 531