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 Addr victim := L2cache.cacheProbe(in_msg.addr); 382 Entry L2cache_entry := getCacheEntry(victim); 383 if (isDirty(L2cache_entry)) { 384 trigger(Event:L2_Replacement, victim, L2cache_entry, TBEs[victim]); 385 } else { 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} 1102