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/* 30 * $Id: MOESI_CMP_token-L1cache.sm 1.22 05/01/19 15:55:39-06:00 beckmann@s0-28.cs.wisc.edu $ 31 * 32 */ 33 34machine(MachineType:L1Cache, "Token protocol") 35 : Sequencer * sequencer; 36 CacheMemory * L1Icache; 37 CacheMemory * L1Dcache; 38 int l2_select_num_bits; 39 int N_tokens; 40 41 Cycles l1_request_latency := 2; 42 Cycles l1_response_latency := 2; 43 int retry_threshold := 1; 44 Cycles fixed_timeout_latency := 100; 45 Cycles reissue_wakeup_latency := 10; 46 Cycles use_timeout_latency := 50; 47 48 bool dynamic_timeout_enabled := "True"; 49 bool no_mig_atomic := "True"; 50 bool send_evictions; 51 52 // Message Queues 53 // From this node's L1 cache TO the network 54 55 // a local L1 -> this L2 bank 56 MessageBuffer * responseFromL1Cache, network="To", virtual_network="4", 57 vnet_type="response"; 58 MessageBuffer * persistentFromL1Cache, network="To", virtual_network="3", 59 vnet_type="persistent"; 60 // a local L1 -> this L2 bank, currently ordered with directory forwarded requests 61 MessageBuffer * requestFromL1Cache, network="To", virtual_network="1", 62 vnet_type="request"; 63 64 // To this node's L1 cache FROM the network 65 66 // a L2 bank -> this L1 67 MessageBuffer * responseToL1Cache, network="From", virtual_network="4", 68 vnet_type="response"; 69 MessageBuffer * persistentToL1Cache, network="From", virtual_network="3", 70 vnet_type="persistent"; 71 // a L2 bank -> this L1 72 MessageBuffer * requestToL1Cache, network="From", virtual_network="1", 73 vnet_type="request"; 74 75 MessageBuffer * mandatoryQueue; 76{ 77 // STATES 78 state_declaration(State, desc="Cache states", default="L1Cache_State_I") { 79 // Base states 80 NP, AccessPermission:Invalid, "NP", desc="Not Present"; 81 I, AccessPermission:Invalid, "I", desc="Idle"; 82 S, AccessPermission:Read_Only, "S", desc="Shared"; 83 O, AccessPermission:Read_Only, "O", desc="Owned"; 84 M, AccessPermission:Read_Only, "M", desc="Modified (dirty)"; 85 MM, AccessPermission:Read_Write, "MM", desc="Modified (dirty and locally modified)"; 86 M_W, AccessPermission:Read_Only, "M^W", desc="Modified (dirty), waiting"; 87 MM_W, AccessPermission:Read_Write, "MM^W", desc="Modified (dirty and locally modified), waiting"; 88 89 // Transient States 90 IM, AccessPermission:Busy, "IM", desc="Issued GetX"; 91 SM, AccessPermission:Read_Only, "SM", desc="Issued GetX, we still have an old copy of the line"; 92 OM, AccessPermission:Read_Only, "OM", desc="Issued GetX, received data"; 93 IS, AccessPermission:Busy, "IS", desc="Issued GetS"; 94 95 // Locked states 96 I_L, AccessPermission:Busy, "I^L", desc="Invalid, Locked"; 97 S_L, AccessPermission:Busy, "S^L", desc="Shared, Locked"; 98 IM_L, AccessPermission:Busy, "IM^L", desc="Invalid, Locked, trying to go to Modified"; 99 SM_L, AccessPermission:Busy, "SM^L", desc="Shared, Locked, trying to go to Modified"; 100 IS_L, AccessPermission:Busy, "IS^L", desc="Invalid, Locked, trying to go to Shared"; 101 } 102 103 // EVENTS 104 enumeration(Event, desc="Cache events") { 105 Load, desc="Load request from the processor"; 106 Ifetch, desc="I-fetch request from the processor"; 107 Store, desc="Store request from the processor"; 108 Atomic, desc="Atomic request from the processor"; 109 L1_Replacement, desc="L1 Replacement"; 110 111 // Responses 112 Data_Shared, desc="Received a data message, we are now a sharer"; 113 Data_Owner, desc="Received a data message, we are now the owner"; 114 Data_All_Tokens, desc="Received a data message, we are now the owner, we now have all the tokens"; 115 Ack, desc="Received an ack message"; 116 Ack_All_Tokens, desc="Received an ack message, we now have all the tokens"; 117 118 // Requests 119 Transient_GETX, desc="A GetX from another processor"; 120 Transient_Local_GETX, desc="A GetX from another processor"; 121 Transient_GETS, desc="A GetS from another processor"; 122 Transient_Local_GETS, desc="A GetS from another processor"; 123 Transient_GETS_Last_Token, desc="A GetS from another processor"; 124 Transient_Local_GETS_Last_Token, desc="A GetS from another processor"; 125 126 // Lock/Unlock for distributed 127 Persistent_GETX, desc="Another processor has priority to read/write"; 128 Persistent_GETS, desc="Another processor has priority to read"; 129 Persistent_GETS_Last_Token, desc="Another processor has priority to read, no more tokens"; 130 Own_Lock_or_Unlock, desc="This processor now has priority"; 131 132 // Triggers 133 Request_Timeout, desc="Timeout"; 134 Use_TimeoutStarverX, desc="Timeout"; 135 Use_TimeoutStarverS, desc="Timeout"; 136 Use_TimeoutNoStarvers, desc="Timeout"; 137 Use_TimeoutNoStarvers_NoMig, desc="Timeout Don't Migrate"; 138 } 139 140 // TYPES 141 142 // CacheEntry 143 structure(Entry, desc="...", interface="AbstractCacheEntry") { 144 State CacheState, desc="cache state"; 145 bool Dirty, desc="Is the data dirty (different than memory)?"; 146 int Tokens, desc="The number of tokens we're holding for the line"; 147 DataBlock DataBlk, desc="data for the block"; 148 } 149 150 151 // TBE fields 152 structure(TBE, desc="...") { 153 Addr addr, desc="Physical address for this TBE"; 154 State TBEState, desc="Transient state"; 155 int IssueCount, default="0", desc="The number of times we've issued a request for this line."; 156 Addr PC, desc="Program counter of request"; 157 158 bool WentPersistent, default="false", desc="Request went persistent"; 159 bool ExternalResponse, default="false", desc="Response came from an external controller"; 160 bool IsAtomic, default="false", desc="Request was an atomic request"; 161 162 AccessType TypeOfAccess, desc="Type of request (used for profiling)"; 163 Cycles IssueTime, desc="Time the request was issued"; 164 RubyAccessMode AccessMode, desc="user/supervisor access type"; 165 PrefetchBit Prefetch, desc="Is this a prefetch request"; 166 } 167 168 structure(TBETable, external="yes") { 169 TBE lookup(Addr); 170 void allocate(Addr); 171 void deallocate(Addr); 172 bool isPresent(Addr); 173 } 174 175 structure(PersistentTable, external="yes") { 176 void persistentRequestLock(Addr, MachineID, AccessType); 177 void persistentRequestUnlock(Addr, MachineID); 178 bool okToIssueStarving(Addr, MachineID); 179 MachineID findSmallest(Addr); 180 AccessType typeOfSmallest(Addr); 181 void markEntries(Addr); 182 bool isLocked(Addr); 183 int countStarvingForAddress(Addr); 184 int countReadStarvingForAddress(Addr); 185 } 186 187 Tick clockEdge(); 188 Tick cyclesToTicks(Cycles c); 189 void set_cache_entry(AbstractCacheEntry b); 190 void unset_cache_entry(); 191 void set_tbe(TBE b); 192 void unset_tbe(); 193 void wakeUpAllBuffers(); 194 void wakeUpBuffers(Addr a); 195 Cycles curCycle(); 196 MachineID mapAddressToMachine(Addr addr, MachineType mtype); 197 198 TBETable L1_TBEs, template="<L1Cache_TBE>", constructor="m_number_of_TBEs"; 199 200 bool starving, default="false"; 201 int l2_select_low_bit, default="RubySystem::getBlockSizeBits()"; 202 203 PersistentTable persistentTable; 204 TimerTable useTimerTable; 205 TimerTable reissueTimerTable; 206 207 int outstandingRequests, default="0"; 208 int outstandingPersistentRequests, default="0"; 209 210 // Constant that provides hysteresis for calculated the estimated average 211 int averageLatencyHysteresis, default="(8)"; 212 Cycles averageLatencyCounter, 213 default="(Cycles(500) << (*m_averageLatencyHysteresis_ptr))"; 214 215 Cycles averageLatencyEstimate() { 216 DPRINTF(RubySlicc, "%d\n", 217 (averageLatencyCounter >> averageLatencyHysteresis)); 218 return averageLatencyCounter >> averageLatencyHysteresis; 219 } 220 221 void updateAverageLatencyEstimate(Cycles latency) { 222 DPRINTF(RubySlicc, "%d\n", latency); 223 224 // By subtracting the current average and then adding the most 225 // recent sample, we calculate an estimate of the recent average. 226 // If we simply used a running sum and divided by the total number 227 // of entries, the estimate of the average would adapt very slowly 228 // after the execution has run for a long time. 229 // averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency; 230 231 averageLatencyCounter := averageLatencyCounter - averageLatencyEstimate() + latency; 232 } 233 234 Entry getCacheEntry(Addr addr), return_by_pointer="yes" { 235 Entry L1Dcache_entry := static_cast(Entry, "pointer", L1Dcache.lookup(addr)); 236 if(is_valid(L1Dcache_entry)) { 237 return L1Dcache_entry; 238 } 239 240 Entry L1Icache_entry := static_cast(Entry, "pointer", L1Icache.lookup(addr)); 241 return L1Icache_entry; 242 } 243 244 void functionalRead(Addr addr, Packet *pkt) { 245 testAndRead(addr, getCacheEntry(addr).DataBlk, pkt); 246 } 247 248 int functionalWrite(Addr addr, Packet *pkt) { 249 int num_functional_writes := 0; 250 num_functional_writes := num_functional_writes + 251 testAndWrite(addr, getCacheEntry(addr).DataBlk, pkt); 252 return num_functional_writes; 253 } 254 255 Entry getL1DCacheEntry(Addr addr), return_by_pointer="yes" { 256 Entry L1Dcache_entry := static_cast(Entry, "pointer", L1Dcache.lookup(addr)); 257 return L1Dcache_entry; 258 } 259 260 Entry getL1ICacheEntry(Addr addr), return_by_pointer="yes" { 261 Entry L1Icache_entry := static_cast(Entry, "pointer", L1Icache.lookup(addr)); 262 return L1Icache_entry; 263 } 264 265 int getTokens(Entry cache_entry) { 266 if (is_valid(cache_entry)) { 267 return cache_entry.Tokens; 268 } 269 return 0; 270 } 271 272 State getState(TBE tbe, Entry cache_entry, Addr addr) { 273 274 if (is_valid(tbe)) { 275 return tbe.TBEState; 276 } else if (is_valid(cache_entry)) { 277 return cache_entry.CacheState; 278 } else { 279 if (persistentTable.isLocked(addr) && (persistentTable.findSmallest(addr) != machineID)) { 280 // Not in cache, in persistent table, but this processor isn't highest priority 281 return State:I_L; 282 } else { 283 return State:NP; 284 } 285 } 286 } 287 288 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) { 289 assert((L1Dcache.isTagPresent(addr) && L1Icache.isTagPresent(addr)) == false); 290 291 if (is_valid(tbe)) { 292 assert(state != State:I); 293 assert(state != State:S); 294 assert(state != State:O); 295 assert(state != State:MM); 296 assert(state != State:M); 297 tbe.TBEState := state; 298 } 299 300 if (is_valid(cache_entry)) { 301 // Make sure the token count is in range 302 assert(cache_entry.Tokens >= 0); 303 assert(cache_entry.Tokens <= max_tokens()); 304 assert(cache_entry.Tokens != (max_tokens() / 2)); 305 306 if ((state == State:I_L) || 307 (state == State:IM_L) || 308 (state == State:IS_L)) { 309 // Make sure we have no tokens in the "Invalid, locked" states 310 assert(cache_entry.Tokens == 0); 311 312 // Make sure the line is locked 313 // assert(persistentTable.isLocked(addr)); 314 315 // But we shouldn't have highest priority for it 316 // assert(persistentTable.findSmallest(addr) != id); 317 318 } else if ((state == State:S_L) || 319 (state == State:SM_L)) { 320 assert(cache_entry.Tokens >= 1); 321 assert(cache_entry.Tokens < (max_tokens() / 2)); 322 323 // Make sure the line is locked... 324 // assert(persistentTable.isLocked(addr)); 325 326 // ...But we shouldn't have highest priority for it... 327 // assert(persistentTable.findSmallest(addr) != id); 328 329 // ...And it must be a GETS request 330 // assert(persistentTable.typeOfSmallest(addr) == AccessType:Read); 331 332 } else { 333 334 // If there is an entry in the persistent table of this block, 335 // this processor needs to have an entry in the table for this 336 // block, and that entry better be the smallest (highest 337 // priority). Otherwise, the state should have been one of 338 // locked states 339 340 //if (persistentTable.isLocked(addr)) { 341 // assert(persistentTable.findSmallest(addr) == id); 342 //} 343 } 344 345 // in M and E you have all the tokens 346 if (state == State:MM || state == State:M || state == State:MM_W || state == State:M_W) { 347 assert(cache_entry.Tokens == max_tokens()); 348 } 349 350 // in NP you have no tokens 351 if (state == State:NP) { 352 assert(cache_entry.Tokens == 0); 353 } 354 355 // You have at least one token in S-like states 356 if (state == State:S || state == State:SM) { 357 assert(cache_entry.Tokens > 0); 358 } 359 360 // You have at least half the token in O-like states 361 if (state == State:O && state == State:OM) { 362 assert(cache_entry.Tokens > (max_tokens() / 2)); 363 } 364 365 cache_entry.CacheState := state; 366 } 367 } 368 369 AccessPermission getAccessPermission(Addr addr) { 370 TBE tbe := L1_TBEs[addr]; 371 if(is_valid(tbe)) { 372 return L1Cache_State_to_permission(tbe.TBEState); 373 } 374 375 Entry cache_entry := getCacheEntry(addr); 376 if(is_valid(cache_entry)) { 377 return L1Cache_State_to_permission(cache_entry.CacheState); 378 } 379 380 return AccessPermission:NotPresent; 381 } 382 383 void setAccessPermission(Entry cache_entry, Addr addr, State state) { 384 if (is_valid(cache_entry)) { 385 cache_entry.changePermission(L1Cache_State_to_permission(state)); 386 } 387 } 388 389 Event mandatory_request_type_to_event(RubyRequestType type) { 390 if (type == RubyRequestType:LD) { 391 return Event:Load; 392 } else if (type == RubyRequestType:IFETCH) { 393 return Event:Ifetch; 394 } else if (type == RubyRequestType:ST) { 395 return Event:Store; 396 } else if (type == RubyRequestType:ATOMIC) { 397 if (no_mig_atomic) { 398 return Event:Atomic; 399 } else { 400 return Event:Store; 401 } 402 } else { 403 error("Invalid RubyRequestType"); 404 } 405 } 406 407 AccessType cache_request_type_to_access_type(RubyRequestType type) { 408 if ((type == RubyRequestType:LD) || (type == RubyRequestType:IFETCH)) { 409 return AccessType:Read; 410 } else if ((type == RubyRequestType:ST) || (type == RubyRequestType:ATOMIC)) { 411 return AccessType:Write; 412 } else { 413 error("Invalid RubyRequestType"); 414 } 415 } 416 417 // NOTE: direct local hits should not call this function 418 bool isExternalHit(Addr addr, MachineID sender) { 419 if (machineIDToMachineType(sender) == MachineType:L1Cache) { 420 return true; 421 } else if (machineIDToMachineType(sender) == MachineType:L2Cache) { 422 423 if (sender == mapAddressToRange(addr, MachineType:L2Cache, 424 l2_select_low_bit, l2_select_num_bits, intToID(0))) { 425 return false; 426 } else { 427 return true; 428 } 429 } 430 431 return true; 432 } 433 434 bool okToIssueStarving(Addr addr, MachineID machineID) { 435 return persistentTable.okToIssueStarving(addr, machineID); 436 } 437 438 void markPersistentEntries(Addr addr) { 439 persistentTable.markEntries(addr); 440 } 441 442 void setExternalResponse(TBE tbe) { 443 assert(is_valid(tbe)); 444 tbe.ExternalResponse := true; 445 } 446 447 bool IsAtomic(TBE tbe) { 448 assert(is_valid(tbe)); 449 return tbe.IsAtomic; 450 } 451 452 // ** OUT_PORTS ** 453 out_port(persistentNetwork_out, PersistentMsg, persistentFromL1Cache); 454 out_port(requestNetwork_out, RequestMsg, requestFromL1Cache); 455 out_port(responseNetwork_out, ResponseMsg, responseFromL1Cache); 456 out_port(requestRecycle_out, RequestMsg, requestToL1Cache); 457 458 // ** IN_PORTS ** 459 460 // Use Timer 461 in_port(useTimerTable_in, Addr, useTimerTable, rank=5) { 462 if (useTimerTable_in.isReady(clockEdge())) { 463 Addr readyAddress := useTimerTable.nextAddress(); 464 TBE tbe := L1_TBEs.lookup(readyAddress); 465 466 if (persistentTable.isLocked(readyAddress) && 467 (persistentTable.findSmallest(readyAddress) != machineID)) { 468 if (persistentTable.typeOfSmallest(readyAddress) == AccessType:Write) { 469 trigger(Event:Use_TimeoutStarverX, readyAddress, 470 getCacheEntry(readyAddress), tbe); 471 } else { 472 trigger(Event:Use_TimeoutStarverS, readyAddress, 473 getCacheEntry(readyAddress), tbe); 474 } 475 } else { 476 if (no_mig_atomic && IsAtomic(tbe)) { 477 trigger(Event:Use_TimeoutNoStarvers_NoMig, readyAddress, 478 getCacheEntry(readyAddress), tbe); 479 } else { 480 trigger(Event:Use_TimeoutNoStarvers, readyAddress, 481 getCacheEntry(readyAddress), tbe); 482 } 483 } 484 } 485 } 486 487 // Reissue Timer 488 in_port(reissueTimerTable_in, Addr, reissueTimerTable, rank=4) { 489 Tick current_time := clockEdge(); 490 if (reissueTimerTable_in.isReady(current_time)) { 491 Addr addr := reissueTimerTable.nextAddress(); 492 trigger(Event:Request_Timeout, addr, getCacheEntry(addr), 493 L1_TBEs.lookup(addr)); 494 } 495 } 496 497 // Persistent Network 498 in_port(persistentNetwork_in, PersistentMsg, persistentToL1Cache, rank=3) { 499 if (persistentNetwork_in.isReady(clockEdge())) { 500 peek(persistentNetwork_in, PersistentMsg, block_on="addr") { 501 assert(in_msg.Destination.isElement(machineID)); 502 503 // Apply the lockdown or unlockdown message to the table 504 if (in_msg.Type == PersistentRequestType:GETX_PERSISTENT) { 505 persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Write); 506 } else if (in_msg.Type == PersistentRequestType:GETS_PERSISTENT) { 507 persistentTable.persistentRequestLock(in_msg.addr, in_msg.Requestor, AccessType:Read); 508 } else if (in_msg.Type == PersistentRequestType:DEACTIVATE_PERSISTENT) { 509 persistentTable.persistentRequestUnlock(in_msg.addr, in_msg.Requestor); 510 } else { 511 error("Unexpected message"); 512 } 513 514 // React to the message based on the current state of the table 515 Entry cache_entry := getCacheEntry(in_msg.addr); 516 TBE tbe := L1_TBEs[in_msg.addr]; 517 518 if (persistentTable.isLocked(in_msg.addr)) { 519 if (persistentTable.findSmallest(in_msg.addr) == machineID) { 520 // Our Own Lock - this processor is highest priority 521 trigger(Event:Own_Lock_or_Unlock, in_msg.addr, 522 cache_entry, tbe); 523 } else { 524 if (persistentTable.typeOfSmallest(in_msg.addr) == AccessType:Read) { 525 if (getTokens(cache_entry) == 1 || 526 getTokens(cache_entry) == (max_tokens() / 2) + 1) { 527 trigger(Event:Persistent_GETS_Last_Token, in_msg.addr, 528 cache_entry, tbe); 529 } else { 530 trigger(Event:Persistent_GETS, in_msg.addr, 531 cache_entry, tbe); 532 } 533 } else { 534 trigger(Event:Persistent_GETX, in_msg.addr, 535 cache_entry, tbe); 536 } 537 } 538 } else { 539 // Unlock case - no entries in the table 540 trigger(Event:Own_Lock_or_Unlock, in_msg.addr, 541 cache_entry, tbe); 542 } 543 } 544 } 545 } 546 547 // Response Network 548 in_port(responseNetwork_in, ResponseMsg, responseToL1Cache, rank=2) { 549 if (responseNetwork_in.isReady(clockEdge())) { 550 peek(responseNetwork_in, ResponseMsg, block_on="addr") { 551 assert(in_msg.Destination.isElement(machineID)); 552 553 Entry cache_entry := getCacheEntry(in_msg.addr); 554 TBE tbe := L1_TBEs[in_msg.addr]; 555 556 // Mark TBE flag if response received off-chip. Use this to update average latency estimate 557 if ( machineIDToMachineType(in_msg.Sender) == MachineType:L2Cache ) { 558 559 if (in_msg.Sender == mapAddressToRange(in_msg.addr, 560 MachineType:L2Cache, l2_select_low_bit, 561 l2_select_num_bits, intToID(0))) { 562 563 // came from an off-chip L2 cache 564 if (is_valid(tbe)) { 565 // L1_TBEs[in_msg.addr].ExternalResponse := true; 566 // profile_offchipL2_response(in_msg.addr); 567 } 568 } 569 else { 570 // profile_onchipL2_response(in_msg.addr ); 571 } 572 } else if ( machineIDToMachineType(in_msg.Sender) == MachineType:Directory ) { 573 if (is_valid(tbe)) { 574 setExternalResponse(tbe); 575 // profile_memory_response( in_msg.addr); 576 } 577 } else if ( machineIDToMachineType(in_msg.Sender) == MachineType:L1Cache) { 578 //if (isLocalProcessor(machineID, in_msg.Sender) == false) { 579 //if (is_valid(tbe)) { 580 // tbe.ExternalResponse := true; 581 // profile_offchipL1_response(in_msg.addr ); 582 //} 583 //} 584 //else { 585 // profile_onchipL1_response(in_msg.addr ); 586 //} 587 } else { 588 error("unexpected SenderMachine"); 589 } 590 591 592 if (getTokens(cache_entry) + in_msg.Tokens != max_tokens()) { 593 if (in_msg.Type == CoherenceResponseType:ACK) { 594 assert(in_msg.Tokens < (max_tokens() / 2)); 595 trigger(Event:Ack, in_msg.addr, cache_entry, tbe); 596 } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER) { 597 trigger(Event:Data_Owner, in_msg.addr, cache_entry, tbe); 598 } else if (in_msg.Type == CoherenceResponseType:DATA_SHARED) { 599 assert(in_msg.Tokens < (max_tokens() / 2)); 600 trigger(Event:Data_Shared, in_msg.addr, cache_entry, tbe); 601 } else { 602 error("Unexpected message"); 603 } 604 } else { 605 if (in_msg.Type == CoherenceResponseType:ACK) { 606 assert(in_msg.Tokens < (max_tokens() / 2)); 607 trigger(Event:Ack_All_Tokens, in_msg.addr, cache_entry, tbe); 608 } else if (in_msg.Type == CoherenceResponseType:DATA_OWNER || in_msg.Type == CoherenceResponseType:DATA_SHARED) { 609 trigger(Event:Data_All_Tokens, in_msg.addr, cache_entry, tbe); 610 } else { 611 error("Unexpected message"); 612 } 613 } 614 } 615 } 616 } 617 618 // Request Network 619 in_port(requestNetwork_in, RequestMsg, requestToL1Cache) { 620 if (requestNetwork_in.isReady(clockEdge())) { 621 peek(requestNetwork_in, RequestMsg, block_on="addr") { 622 assert(in_msg.Destination.isElement(machineID)); 623 624 Entry cache_entry := getCacheEntry(in_msg.addr); 625 TBE tbe := L1_TBEs[in_msg.addr]; 626 627 if (in_msg.Type == CoherenceRequestType:GETX) { 628 if (in_msg.isLocal) { 629 trigger(Event:Transient_Local_GETX, in_msg.addr, 630 cache_entry, tbe); 631 } 632 else { 633 trigger(Event:Transient_GETX, in_msg.addr, 634 cache_entry, tbe); 635 } 636 } else if (in_msg.Type == CoherenceRequestType:GETS) { 637 if (getTokens(cache_entry) == 1 || 638 getTokens(cache_entry) == (max_tokens() / 2) + 1) { 639 if (in_msg.isLocal) { 640 trigger(Event:Transient_Local_GETS_Last_Token, in_msg.addr, 641 cache_entry, tbe); 642 } 643 else { 644 trigger(Event:Transient_GETS_Last_Token, in_msg.addr, 645 cache_entry, tbe); 646 } 647 } 648 else { 649 if (in_msg.isLocal) { 650 trigger(Event:Transient_Local_GETS, in_msg.addr, 651 cache_entry, tbe); 652 } 653 else { 654 trigger(Event:Transient_GETS, in_msg.addr, 655 cache_entry, tbe); 656 } 657 } 658 } else { 659 error("Unexpected message"); 660 } 661 } 662 } 663 } 664 665 // Mandatory Queue 666 in_port(mandatoryQueue_in, RubyRequest, mandatoryQueue, desc="...", rank=0) { 667 if (mandatoryQueue_in.isReady(clockEdge())) { 668 peek(mandatoryQueue_in, RubyRequest, block_on="LineAddress") { 669 // Check for data access to blocks in I-cache and ifetchs to blocks in D-cache 670 671 TBE tbe := L1_TBEs[in_msg.LineAddress]; 672 673 if (in_msg.Type == RubyRequestType:IFETCH) { 674 // ** INSTRUCTION ACCESS *** 675 676 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); 677 if (is_valid(L1Icache_entry)) { 678 // The tag matches for the L1, so the L1 fetches the line. 679 // We know it can't be in the L2 due to exclusion. 680 trigger(mandatory_request_type_to_event(in_msg.Type), 681 in_msg.LineAddress, L1Icache_entry, tbe); 682 } else { 683 684 // Check to see if it is in the OTHER L1 685 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); 686 if (is_valid(L1Dcache_entry)) { 687 // The block is in the wrong L1, try to write it to the L2 688 trigger(Event:L1_Replacement, in_msg.LineAddress, 689 L1Dcache_entry, tbe); 690 } 691 692 if (L1Icache.cacheAvail(in_msg.LineAddress)) { 693 // L1 does't have the line, but we have space for it in the L1 694 trigger(mandatory_request_type_to_event(in_msg.Type), 695 in_msg.LineAddress, L1Icache_entry, tbe); 696 } else { 697 // No room in the L1, so we need to make room 698 trigger(Event:L1_Replacement, 699 Addr victim := L1Icache.cacheProbe(in_msg.LineAddress); 700 trigger(Event:L1_Replacement, 701 victim, getL1ICacheEntry(victim), L1_TBEs[victim]); 702 } 703 } 704 } else { 705 // *** DATA ACCESS *** 706 707 Entry L1Dcache_entry := getL1DCacheEntry(in_msg.LineAddress); 708 if (is_valid(L1Dcache_entry)) { 709 // The tag matches for the L1, so the L1 fetches the line. 710 // We know it can't be in the L2 due to exclusion. 711 trigger(mandatory_request_type_to_event(in_msg.Type), 712 in_msg.LineAddress, L1Dcache_entry, tbe); 713 } else { 714 715 // Check to see if it is in the OTHER L1 716 Entry L1Icache_entry := getL1ICacheEntry(in_msg.LineAddress); 717 if (is_valid(L1Icache_entry)) { 718 // The block is in the wrong L1, try to write it to the L2 719 trigger(Event:L1_Replacement, in_msg.LineAddress, 720 L1Icache_entry, tbe); 721 } 722 723 if (L1Dcache.cacheAvail(in_msg.LineAddress)) { 724 // L1 does't have the line, but we have space for it in the L1 725 trigger(mandatory_request_type_to_event(in_msg.Type), 726 in_msg.LineAddress, L1Dcache_entry, tbe); 727 } else { 728 // No room in the L1, so we need to make room 729 Addr victim := L1Dcache.cacheProbe(in_msg.LineAddress); 730 trigger(Event:L1_Replacement, 731 victim, getL1DCacheEntry(victim), L1_TBEs[victim]); 732 } 733 } 734 } 735 } 736 } 737 } 738 739 // ACTIONS 740 741 action(a_issueReadRequest, "a", desc="Issue GETS") { 742 assert(is_valid(tbe)); 743 if (tbe.IssueCount == 0) { 744 // Update outstanding requests 745 //profile_outstanding_request(outstandingRequests); 746 outstandingRequests := outstandingRequests + 1; 747 } 748 749 if (tbe.IssueCount >= retry_threshold) { 750 // Issue a persistent request if possible 751 if (okToIssueStarving(address, machineID) && (starving == false)) { 752 enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) { 753 out_msg.addr := address; 754 out_msg.Type := PersistentRequestType:GETS_PERSISTENT; 755 out_msg.Requestor := machineID; 756 out_msg.Destination.broadcast(MachineType:L1Cache); 757 758 // 759 // Currently the configuration system limits the system to only one 760 // chip. Therefore, if we assume one shared L2 cache, then only one 761 // pertinent L2 cache exist. 762 // 763 //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address)); 764 765 out_msg.Destination.add(mapAddressToRange(address, 766 MachineType:L2Cache, l2_select_low_bit, 767 l2_select_num_bits, intToID(0))); 768 769 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 770 out_msg.MessageSize := MessageSizeType:Persistent_Control; 771 out_msg.Prefetch := tbe.Prefetch; 772 out_msg.AccessMode := tbe.AccessMode; 773 } 774 markPersistentEntries(address); 775 starving := true; 776 777 if (tbe.IssueCount == 0) { 778 //profile_persistent_prediction(address, tbe.TypeOfAccess); 779 } 780 781 // Update outstanding requests 782 //profile_outstanding_persistent_request(outstandingPersistentRequests); 783 outstandingPersistentRequests := outstandingPersistentRequests + 1; 784 785 // Increment IssueCount 786 tbe.IssueCount := tbe.IssueCount + 1; 787 788 tbe.WentPersistent := true; 789 790 // Do not schedule a wakeup, a persistent requests will always complete 791 } 792 else { 793 794 // We'd like to issue a persistent request, but are not allowed 795 // to issue a P.R. right now. This, we do not increment the 796 // IssueCount. 797 798 // Set a wakeup timer 799 reissueTimerTable.set( 800 address, clockEdge() + cyclesToTicks(reissue_wakeup_latency)); 801 802 } 803 } else { 804 // Make a normal request 805 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) { 806 out_msg.addr := address; 807 out_msg.Type := CoherenceRequestType:GETS; 808 out_msg.Requestor := machineID; 809 out_msg.Destination.add(mapAddressToRange(address, 810 MachineType:L2Cache, l2_select_low_bit, 811 l2_select_num_bits, intToID(0))); 812 813 out_msg.RetryNum := tbe.IssueCount; 814 if (tbe.IssueCount == 0) { 815 out_msg.MessageSize := MessageSizeType:Request_Control; 816 } else { 817 out_msg.MessageSize := MessageSizeType:Reissue_Control; 818 } 819 out_msg.Prefetch := tbe.Prefetch; 820 out_msg.AccessMode := tbe.AccessMode; 821 } 822 823 // send to other local L1s, with local bit set 824 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) { 825 out_msg.addr := address; 826 out_msg.Type := CoherenceRequestType:GETS; 827 out_msg.Requestor := machineID; 828 // 829 // Since only one chip, assuming all L1 caches are local 830 // 831 //out_msg.Destination := getOtherLocalL1IDs(machineID); 832 out_msg.Destination.broadcast(MachineType:L1Cache); 833 out_msg.Destination.remove(machineID); 834 835 out_msg.RetryNum := tbe.IssueCount; 836 out_msg.isLocal := true; 837 if (tbe.IssueCount == 0) { 838 out_msg.MessageSize := MessageSizeType:Broadcast_Control; 839 } else { 840 out_msg.MessageSize := MessageSizeType:Broadcast_Control; 841 } 842 out_msg.Prefetch := tbe.Prefetch; 843 out_msg.AccessMode := tbe.AccessMode; 844 } 845 846 // Increment IssueCount 847 tbe.IssueCount := tbe.IssueCount + 1; 848 849 // Set a wakeup timer 850 851 if (dynamic_timeout_enabled) { 852 reissueTimerTable.set( 853 address, clockEdge() + cyclesToTicks(averageLatencyEstimate())); 854 } else { 855 reissueTimerTable.set( 856 address, clockEdge() + cyclesToTicks(fixed_timeout_latency)); 857 } 858 859 } 860 } 861 862 action(b_issueWriteRequest, "b", desc="Issue GETX") { 863 864 assert(is_valid(tbe)); 865 if (tbe.IssueCount == 0) { 866 // Update outstanding requests 867 //profile_outstanding_request(outstandingRequests); 868 outstandingRequests := outstandingRequests + 1; 869 } 870 871 if (tbe.IssueCount >= retry_threshold) { 872 // Issue a persistent request if possible 873 if ( okToIssueStarving(address, machineID) && (starving == false)) { 874 enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) { 875 out_msg.addr := address; 876 out_msg.Type := PersistentRequestType:GETX_PERSISTENT; 877 out_msg.Requestor := machineID; 878 out_msg.Destination.broadcast(MachineType:L1Cache); 879 880 // 881 // Currently the configuration system limits the system to only one 882 // chip. Therefore, if we assume one shared L2 cache, then only one 883 // pertinent L2 cache exist. 884 // 885 //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address)); 886 887 out_msg.Destination.add(mapAddressToRange(address, 888 MachineType:L2Cache, l2_select_low_bit, 889 l2_select_num_bits, intToID(0))); 890 891 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 892 out_msg.MessageSize := MessageSizeType:Persistent_Control; 893 out_msg.Prefetch := tbe.Prefetch; 894 out_msg.AccessMode := tbe.AccessMode; 895 } 896 markPersistentEntries(address); 897 starving := true; 898 899 // Update outstanding requests 900 //profile_outstanding_persistent_request(outstandingPersistentRequests); 901 outstandingPersistentRequests := outstandingPersistentRequests + 1; 902 903 if (tbe.IssueCount == 0) { 904 //profile_persistent_prediction(address, tbe.TypeOfAccess); 905 } 906 907 // Increment IssueCount 908 tbe.IssueCount := tbe.IssueCount + 1; 909 910 tbe.WentPersistent := true; 911 912 // Do not schedule a wakeup, a persistent requests will always complete 913 } 914 else { 915 916 // We'd like to issue a persistent request, but are not allowed 917 // to issue a P.R. right now. This, we do not increment the 918 // IssueCount. 919 920 // Set a wakeup timer 921 reissueTimerTable.set( 922 address, clockEdge() + cyclesToTicks(reissue_wakeup_latency)); 923 } 924 925 } else { 926 // Make a normal request 927 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) { 928 out_msg.addr := address; 929 out_msg.Type := CoherenceRequestType:GETX; 930 out_msg.Requestor := machineID; 931 932 out_msg.Destination.add(mapAddressToRange(address, 933 MachineType:L2Cache, l2_select_low_bit, 934 l2_select_num_bits, intToID(0))); 935 936 out_msg.RetryNum := tbe.IssueCount; 937 938 if (tbe.IssueCount == 0) { 939 out_msg.MessageSize := MessageSizeType:Request_Control; 940 } else { 941 out_msg.MessageSize := MessageSizeType:Reissue_Control; 942 } 943 out_msg.Prefetch := tbe.Prefetch; 944 out_msg.AccessMode := tbe.AccessMode; 945 } 946 947 // send to other local L1s too 948 enqueue(requestNetwork_out, RequestMsg, l1_request_latency) { 949 out_msg.addr := address; 950 out_msg.Type := CoherenceRequestType:GETX; 951 out_msg.Requestor := machineID; 952 out_msg.isLocal := true; 953 954 // 955 // Since only one chip, assuming all L1 caches are local 956 // 957 //out_msg.Destination := getOtherLocalL1IDs(machineID); 958 out_msg.Destination.broadcast(MachineType:L1Cache); 959 out_msg.Destination.remove(machineID); 960 961 out_msg.RetryNum := tbe.IssueCount; 962 if (tbe.IssueCount == 0) { 963 out_msg.MessageSize := MessageSizeType:Broadcast_Control; 964 } else { 965 out_msg.MessageSize := MessageSizeType:Broadcast_Control; 966 } 967 out_msg.Prefetch := tbe.Prefetch; 968 out_msg.AccessMode := tbe.AccessMode; 969 } 970 971 // Increment IssueCount 972 tbe.IssueCount := tbe.IssueCount + 1; 973 974 DPRINTF(RubySlicc, "incremented issue count to %d\n", 975 tbe.IssueCount); 976 977 // Set a wakeup timer 978 if (dynamic_timeout_enabled) { 979 reissueTimerTable.set( 980 address, clockEdge() + cyclesToTicks(averageLatencyEstimate())); 981 } else { 982 reissueTimerTable.set( 983 address, clockEdge() + cyclesToTicks(fixed_timeout_latency)); 984 } 985 } 986 } 987 988 action(bb_bounceResponse, "\b", desc="Bounce tokens and data to memory") { 989 peek(responseNetwork_in, ResponseMsg) { 990 // FIXME, should use a 3rd vnet 991 enqueue(responseNetwork_out, ResponseMsg, 1) { 992 out_msg.addr := address; 993 out_msg.Type := in_msg.Type; 994 out_msg.Sender := machineID; 995 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 996 out_msg.Tokens := in_msg.Tokens; 997 out_msg.MessageSize := in_msg.MessageSize; 998 out_msg.DataBlk := in_msg.DataBlk; 999 out_msg.Dirty := in_msg.Dirty; 1000 } 1001 } 1002 } 1003 1004 action(c_ownedReplacement, "c", desc="Issue writeback") { 1005 assert(is_valid(cache_entry)); 1006 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1007 out_msg.addr := address; 1008 out_msg.Sender := machineID; 1009 1010 out_msg.Destination.add(mapAddressToRange(address, 1011 MachineType:L2Cache, l2_select_low_bit, 1012 l2_select_num_bits, intToID(0))); 1013 1014 out_msg.Tokens := cache_entry.Tokens; 1015 out_msg.DataBlk := cache_entry.DataBlk; 1016 out_msg.Dirty := cache_entry.Dirty; 1017 out_msg.Type := CoherenceResponseType:WB_OWNED; 1018 1019 // always send the data? 1020 out_msg.MessageSize := MessageSizeType:Writeback_Data; 1021 } 1022 cache_entry.Tokens := 0; 1023 } 1024 1025 action(cc_sharedReplacement, "\c", desc="Issue shared writeback") { 1026 1027 // don't send writeback if replacing block with no tokens 1028 assert(is_valid(cache_entry)); 1029 assert (cache_entry.Tokens > 0); 1030 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1031 out_msg.addr := address; 1032 out_msg.Sender := machineID; 1033 1034 out_msg.Destination.add(mapAddressToRange(address, 1035 MachineType:L2Cache, l2_select_low_bit, 1036 l2_select_num_bits, intToID(0))); 1037 1038 out_msg.Tokens := cache_entry.Tokens; 1039 out_msg.DataBlk := cache_entry.DataBlk; 1040 // assert(cache_entry.Dirty == false); 1041 out_msg.Dirty := false; 1042 1043 out_msg.MessageSize := MessageSizeType:Writeback_Data; 1044 out_msg.Type := CoherenceResponseType:WB_SHARED_DATA; 1045 } 1046 cache_entry.Tokens := 0; 1047 } 1048 1049 action(tr_tokenReplacement, "tr", desc="Issue token writeback") { 1050 assert(is_valid(cache_entry)); 1051 if (cache_entry.Tokens > 0) { 1052 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1053 out_msg.addr := address; 1054 out_msg.Sender := machineID; 1055 1056 out_msg.Destination.add(mapAddressToRange(address, 1057 MachineType:L2Cache, l2_select_low_bit, 1058 l2_select_num_bits, intToID(0))); 1059 1060 out_msg.Tokens := cache_entry.Tokens; 1061 out_msg.DataBlk := cache_entry.DataBlk; 1062 // assert(cache_entry.Dirty == false); 1063 out_msg.Dirty := false; 1064 1065 // always send the data? 1066 out_msg.MessageSize := MessageSizeType:Writeback_Control; 1067 out_msg.Type := CoherenceResponseType:WB_TOKENS; 1068 } 1069 } 1070 cache_entry.Tokens := 0; 1071 } 1072 1073 1074 action(d_sendDataWithToken, "d", desc="Send data and a token from cache to requestor") { 1075 assert(is_valid(cache_entry)); 1076 peek(requestNetwork_in, RequestMsg) { 1077 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1078 out_msg.addr := address; 1079 out_msg.Type := CoherenceResponseType:DATA_SHARED; 1080 out_msg.Sender := machineID; 1081 out_msg.Destination.add(in_msg.Requestor); 1082 out_msg.Tokens := 1; 1083 out_msg.DataBlk := cache_entry.DataBlk; 1084 // out_msg.Dirty := cache_entry.Dirty; 1085 out_msg.Dirty := false; 1086 if (in_msg.isLocal) { 1087 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; 1088 } else { 1089 out_msg.MessageSize := MessageSizeType:Response_Data; 1090 } 1091 } 1092 } 1093 cache_entry.Tokens := cache_entry.Tokens - 1; 1094 assert(cache_entry.Tokens >= 1); 1095 } 1096 1097 action(d_sendDataWithNTokenIfAvail, "\dd", desc="Send data and a token from cache to requestor") { 1098 assert(is_valid(cache_entry)); 1099 peek(requestNetwork_in, RequestMsg) { 1100 if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { 1101 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1102 out_msg.addr := address; 1103 out_msg.Type := CoherenceResponseType:DATA_SHARED; 1104 out_msg.Sender := machineID; 1105 out_msg.Destination.add(in_msg.Requestor); 1106 out_msg.Tokens := N_tokens; 1107 out_msg.DataBlk := cache_entry.DataBlk; 1108 // out_msg.Dirty := cache_entry.Dirty; 1109 out_msg.Dirty := false; 1110 if (in_msg.isLocal) { 1111 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; 1112 } else { 1113 out_msg.MessageSize := MessageSizeType:Response_Data; 1114 } 1115 } 1116 cache_entry.Tokens := cache_entry.Tokens - N_tokens; 1117 } 1118 else if (cache_entry.Tokens > 1) { 1119 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1120 out_msg.addr := address; 1121 out_msg.Type := CoherenceResponseType:DATA_SHARED; 1122 out_msg.Sender := machineID; 1123 out_msg.Destination.add(in_msg.Requestor); 1124 out_msg.Tokens := 1; 1125 out_msg.DataBlk := cache_entry.DataBlk; 1126 // out_msg.Dirty := cache_entry.Dirty; 1127 out_msg.Dirty := false; 1128 if (in_msg.isLocal) { 1129 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; 1130 } else { 1131 out_msg.MessageSize := MessageSizeType:Response_Data; 1132 } 1133 } 1134 cache_entry.Tokens := cache_entry.Tokens - 1; 1135 } 1136 } 1137// assert(cache_entry.Tokens >= 1); 1138 } 1139 1140 action(dd_sendDataWithAllTokens, "\d", desc="Send data and all tokens from cache to requestor") { 1141 peek(requestNetwork_in, RequestMsg) { 1142 assert(is_valid(cache_entry)); 1143 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1144 out_msg.addr := address; 1145 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1146 out_msg.Sender := machineID; 1147 out_msg.Destination.add(in_msg.Requestor); 1148 assert(cache_entry.Tokens > (max_tokens() / 2)); 1149 out_msg.Tokens := cache_entry.Tokens; 1150 out_msg.DataBlk := cache_entry.DataBlk; 1151 out_msg.Dirty := cache_entry.Dirty; 1152 if (in_msg.isLocal) { 1153 out_msg.MessageSize := MessageSizeType:ResponseLocal_Data; 1154 } else { 1155 out_msg.MessageSize := MessageSizeType:Response_Data; 1156 } 1157 } 1158 } 1159 cache_entry.Tokens := 0; 1160 } 1161 1162 action(e_sendAckWithCollectedTokens, "e", desc="Send ack with the tokens we've collected thus far.") { 1163 // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself 1164 assert(is_valid(cache_entry)); 1165 if (cache_entry.Tokens > 0) { 1166 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1167 out_msg.addr := address; 1168 if (cache_entry.Tokens > (max_tokens() / 2)) { 1169 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1170 } else { 1171 out_msg.Type := CoherenceResponseType:ACK; 1172 } 1173 out_msg.Sender := machineID; 1174 out_msg.Destination.add(persistentTable.findSmallest(address)); 1175 assert(cache_entry.Tokens >= 1); 1176 out_msg.Tokens := cache_entry.Tokens; 1177 out_msg.DataBlk := cache_entry.DataBlk; 1178 out_msg.MessageSize := MessageSizeType:Response_Control; 1179 } 1180 } 1181 cache_entry.Tokens := 0; 1182 } 1183 1184 action(ee_sendDataWithAllTokens, "\e", desc="Send data and all tokens from cache to starver") { 1185 //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself 1186 assert(is_valid(cache_entry)); 1187 assert(cache_entry.Tokens > 0); 1188 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1189 out_msg.addr := address; 1190 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1191 out_msg.Sender := machineID; 1192 out_msg.Destination.add(persistentTable.findSmallest(address)); 1193 assert(cache_entry.Tokens > (max_tokens() / 2)); 1194 out_msg.Tokens := cache_entry.Tokens; 1195 out_msg.DataBlk := cache_entry.DataBlk; 1196 out_msg.Dirty := cache_entry.Dirty; 1197 out_msg.MessageSize := MessageSizeType:Response_Data; 1198 } 1199 cache_entry.Tokens := 0; 1200 } 1201 1202 action(f_sendAckWithAllButNorOneTokens, "f", desc="Send ack with all our tokens but one to starver.") { 1203 //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself 1204 assert(is_valid(cache_entry)); 1205 assert(cache_entry.Tokens > 0); 1206 if (cache_entry.Tokens > 1) { 1207 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1208 out_msg.addr := address; 1209 if (cache_entry.Tokens > (max_tokens() / 2)) { 1210 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1211 } else { 1212 out_msg.Type := CoherenceResponseType:ACK; 1213 } 1214 out_msg.Sender := machineID; 1215 out_msg.Destination.add(persistentTable.findSmallest(address)); 1216 assert(cache_entry.Tokens >= 1); 1217 if (cache_entry.Tokens > N_tokens) { 1218 out_msg.Tokens := cache_entry.Tokens - N_tokens; 1219 } else { 1220 out_msg.Tokens := cache_entry.Tokens - 1; 1221 } 1222 out_msg.DataBlk := cache_entry.DataBlk; 1223 out_msg.MessageSize := MessageSizeType:Response_Control; 1224 } 1225 } 1226 if (cache_entry.Tokens > N_tokens) { 1227 cache_entry.Tokens := N_tokens; 1228 } else { 1229 cache_entry.Tokens := 1; 1230 } 1231 } 1232 1233 action(ff_sendDataWithAllButNorOneTokens, "\f", desc="Send data and out tokens but one to starver") { 1234 //assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself 1235 assert(is_valid(cache_entry)); 1236 assert(cache_entry.Tokens > ((max_tokens() / 2) + 1)); 1237 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1238 out_msg.addr := address; 1239 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1240 out_msg.Sender := machineID; 1241 out_msg.Destination.add(persistentTable.findSmallest(address)); 1242 if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { 1243 out_msg.Tokens := cache_entry.Tokens - N_tokens; 1244 } else { 1245 out_msg.Tokens := cache_entry.Tokens - 1; 1246 } 1247 assert(out_msg.Tokens > (max_tokens() / 2)); 1248 out_msg.DataBlk := cache_entry.DataBlk; 1249 out_msg.Dirty := cache_entry.Dirty; 1250 out_msg.MessageSize := MessageSizeType:Response_Data; 1251 } 1252 if (cache_entry.Tokens > (N_tokens + (max_tokens() / 2))) { 1253 cache_entry.Tokens := N_tokens; 1254 } else { 1255 cache_entry.Tokens := 1; 1256 } 1257 } 1258 1259 action(fo_sendDataWithOwnerToken, "fo", desc="Send data and owner tokens") { 1260 assert(is_valid(cache_entry)); 1261 assert(cache_entry.Tokens == ((max_tokens() / 2) + 1)); 1262 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1263 out_msg.addr := address; 1264 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1265 out_msg.Sender := machineID; 1266 out_msg.Destination.add(persistentTable.findSmallest(address)); 1267 out_msg.Tokens := cache_entry.Tokens; 1268 assert(out_msg.Tokens > (max_tokens() / 2)); 1269 out_msg.DataBlk := cache_entry.DataBlk; 1270 out_msg.Dirty := cache_entry.Dirty; 1271 out_msg.MessageSize := MessageSizeType:Response_Data; 1272 } 1273 cache_entry.Tokens := 0; 1274 } 1275 1276 action(g_bounceResponseToStarver, "g", desc="Redirect response to starving processor") { 1277 // assert(persistentTable.isLocked(address)); 1278 1279 peek(responseNetwork_in, ResponseMsg) { 1280 // assert(persistentTable.findSmallest(address) != id); // Make sure we never bounce tokens to ourself 1281 // FIXME, should use a 3rd vnet in some cases 1282 enqueue(responseNetwork_out, ResponseMsg, 1) { 1283 out_msg.addr := address; 1284 out_msg.Type := in_msg.Type; 1285 out_msg.Sender := machineID; 1286 out_msg.Destination.add(persistentTable.findSmallest(address)); 1287 out_msg.Tokens := in_msg.Tokens; 1288 out_msg.DataBlk := in_msg.DataBlk; 1289 out_msg.Dirty := in_msg.Dirty; 1290 out_msg.MessageSize := in_msg.MessageSize; 1291 } 1292 } 1293 } 1294 1295 action(h_load_hit, "hd", desc="Notify sequencer the load completed.") { 1296 assert(is_valid(cache_entry)); 1297 DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n", 1298 address, cache_entry.DataBlk); 1299 1300 L1Dcache.setMRU(cache_entry); 1301 sequencer.readCallback(address, cache_entry.DataBlk, false, 1302 MachineType:L1Cache); 1303 } 1304 1305 action(h_ifetch_hit, "hi", desc="Notify sequencer the load completed.") { 1306 assert(is_valid(cache_entry)); 1307 DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n", 1308 address, cache_entry.DataBlk); 1309 1310 L1Icache.setMRU(cache_entry); 1311 sequencer.readCallback(address, cache_entry.DataBlk, false, 1312 MachineType:L1Cache); 1313 } 1314 1315 action(x_external_load_hit, "x", desc="Notify sequencer the load completed.") { 1316 assert(is_valid(cache_entry)); 1317 DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n", 1318 address, cache_entry.DataBlk); 1319 peek(responseNetwork_in, ResponseMsg) { 1320 L1Icache.setMRU(address); 1321 L1Dcache.setMRU(address); 1322 sequencer.readCallback(address, cache_entry.DataBlk, 1323 isExternalHit(address, in_msg.Sender), 1324 machineIDToMachineType(in_msg.Sender)); 1325 } 1326 } 1327 1328 action(hh_store_hit, "\h", desc="Notify sequencer that store completed.") { 1329 assert(is_valid(cache_entry)); 1330 DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n", 1331 address, cache_entry.DataBlk); 1332 1333 L1Dcache.setMRU(cache_entry); 1334 sequencer.writeCallback(address, cache_entry.DataBlk, false, 1335 MachineType:L1Cache); 1336 cache_entry.Dirty := true; 1337 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); 1338 } 1339 1340 action(xx_external_store_hit, "\x", desc="Notify sequencer that store completed.") { 1341 assert(is_valid(cache_entry)); 1342 DPRINTF(RubySlicc, "Address: %#x, Data Block: %s\n", 1343 address, cache_entry.DataBlk); 1344 peek(responseNetwork_in, ResponseMsg) { 1345 L1Icache.setMRU(address); 1346 L1Dcache.setMRU(address); 1347 sequencer.writeCallback(address, cache_entry.DataBlk, 1348 isExternalHit(address, in_msg.Sender), 1349 machineIDToMachineType(in_msg.Sender)); 1350 } 1351 cache_entry.Dirty := true; 1352 DPRINTF(RubySlicc, "%s\n", cache_entry.DataBlk); 1353 } 1354 1355 action(i_allocateTBE, "i", desc="Allocate TBE") { 1356 check_allocate(L1_TBEs); 1357 L1_TBEs.allocate(address); 1358 set_tbe(L1_TBEs[address]); 1359 tbe.IssueCount := 0; 1360 peek(mandatoryQueue_in, RubyRequest) { 1361 tbe.PC := in_msg.ProgramCounter; 1362 tbe.TypeOfAccess := cache_request_type_to_access_type(in_msg.Type); 1363 if (in_msg.Type == RubyRequestType:ATOMIC) { 1364 tbe.IsAtomic := true; 1365 } 1366 tbe.Prefetch := in_msg.Prefetch; 1367 tbe.AccessMode := in_msg.AccessMode; 1368 } 1369 tbe.IssueTime := curCycle(); 1370 } 1371 1372 action(ta_traceStalledAddress, "ta", desc="Trace Stalled Address") { 1373 peek(mandatoryQueue_in, RubyRequest) { 1374 APPEND_TRANSITION_COMMENT(in_msg.LineAddress); 1375 } 1376 } 1377 1378 action(j_unsetReissueTimer, "j", desc="Unset reissue timer.") { 1379 if (reissueTimerTable.isSet(address)) { 1380 reissueTimerTable.unset(address); 1381 } 1382 } 1383 1384 action(jj_unsetUseTimer, "\j", desc="Unset use timer.") { 1385 useTimerTable.unset(address); 1386 } 1387 1388 action(k_popMandatoryQueue, "k", desc="Pop mandatory queue.") { 1389 mandatoryQueue_in.dequeue(clockEdge()); 1390 } 1391 1392 action(l_popPersistentQueue, "l", desc="Pop persistent queue.") { 1393 persistentNetwork_in.dequeue(clockEdge()); 1394 } 1395 1396 action(m_popRequestQueue, "m", desc="Pop request queue.") { 1397 requestNetwork_in.dequeue(clockEdge()); 1398 } 1399 1400 action(n_popResponseQueue, "n", desc="Pop response queue") { 1401 responseNetwork_in.dequeue(clockEdge()); 1402 } 1403 1404 action(o_scheduleUseTimeout, "o", desc="Schedule a use timeout.") { 1405 useTimerTable.set( 1406 address, clockEdge() + cyclesToTicks(use_timeout_latency)); 1407 } 1408 1409 action(p_informL2AboutTokenLoss, "p", desc="Inform L2 about loss of all tokens") { 1410 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1411 out_msg.addr := address; 1412 out_msg.Type := CoherenceResponseType:INV; 1413 out_msg.Tokens := 0; 1414 out_msg.Sender := machineID; 1415 1416 out_msg.Destination.add(mapAddressToRange(address, 1417 MachineType:L2Cache, l2_select_low_bit, 1418 l2_select_num_bits, intToID(0))); 1419 out_msg.MessageSize := MessageSizeType:Response_Control; 1420 } 1421 } 1422 1423 action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") { 1424 peek(responseNetwork_in, ResponseMsg) { 1425 assert(is_valid(cache_entry)); 1426 assert(in_msg.Tokens != 0); 1427 DPRINTF(RubySlicc, "L1 received tokens for address: %#x, tokens: %d\n", 1428 in_msg.addr, in_msg.Tokens); 1429 cache_entry.Tokens := cache_entry.Tokens + in_msg.Tokens; 1430 DPRINTF(RubySlicc, "%d\n", cache_entry.Tokens); 1431 1432 if (cache_entry.Dirty == false && in_msg.Dirty) { 1433 cache_entry.Dirty := true; 1434 } 1435 } 1436 } 1437 1438 action(s_deallocateTBE, "s", desc="Deallocate TBE") { 1439 1440 assert(is_valid(tbe)); 1441 if (tbe.WentPersistent) { 1442 // assert(starving); 1443 outstandingRequests := outstandingRequests - 1; 1444 enqueue(persistentNetwork_out, PersistentMsg, l1_request_latency) { 1445 out_msg.addr := address; 1446 out_msg.Type := PersistentRequestType:DEACTIVATE_PERSISTENT; 1447 out_msg.Requestor := machineID; 1448 out_msg.Destination.broadcast(MachineType:L1Cache); 1449 1450 // 1451 // Currently the configuration system limits the system to only one 1452 // chip. Therefore, if we assume one shared L2 cache, then only one 1453 // pertinent L2 cache exist. 1454 // 1455 //out_msg.Destination.addNetDest(getAllPertinentL2Banks(address)); 1456 1457 out_msg.Destination.add(mapAddressToRange(address, 1458 MachineType:L2Cache, l2_select_low_bit, 1459 l2_select_num_bits, intToID(0))); 1460 1461 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 1462 out_msg.MessageSize := MessageSizeType:Persistent_Control; 1463 } 1464 starving := false; 1465 } 1466 1467 // Update average latency 1468 if (tbe.IssueCount <= 1) { 1469 if (tbe.ExternalResponse) { 1470 updateAverageLatencyEstimate(curCycle() - tbe.IssueTime); 1471 } 1472 } 1473 1474 // Profile 1475 //if (tbe.WentPersistent) { 1476 // profile_token_retry(address, tbe.TypeOfAccess, 2); 1477 //} 1478 //else { 1479 // profile_token_retry(address, tbe.TypeOfAccess, 1); 1480 //} 1481 1482 //profile_token_retry(address, tbe.TypeOfAccess, tbe.IssueCount); 1483 L1_TBEs.deallocate(address); 1484 unset_tbe(); 1485 } 1486 1487 action(t_sendAckWithCollectedTokens, "t", desc="Send ack with the tokens we've collected thus far.") { 1488 assert(is_valid(cache_entry)); 1489 if (cache_entry.Tokens > 0) { 1490 peek(requestNetwork_in, RequestMsg) { 1491 enqueue(responseNetwork_out, ResponseMsg, l1_response_latency) { 1492 out_msg.addr := address; 1493 if (cache_entry.Tokens > (max_tokens() / 2)) { 1494 out_msg.Type := CoherenceResponseType:DATA_OWNER; 1495 } else { 1496 out_msg.Type := CoherenceResponseType:ACK; 1497 } 1498 out_msg.Sender := machineID; 1499 out_msg.Destination.add(in_msg.Requestor); 1500 assert(cache_entry.Tokens >= 1); 1501 out_msg.Tokens := cache_entry.Tokens; 1502 out_msg.DataBlk := cache_entry.DataBlk; 1503 out_msg.MessageSize := MessageSizeType:Response_Control; 1504 } 1505 } 1506 } 1507 cache_entry.Tokens := 0; 1508 } 1509 1510 action(u_writeDataToCache, "u", desc="Write data to cache") { 1511 peek(responseNetwork_in, ResponseMsg) { 1512 assert(is_valid(cache_entry)); 1513 cache_entry.DataBlk := in_msg.DataBlk; 1514 if (cache_entry.Dirty == false && in_msg.Dirty) { 1515 cache_entry.Dirty := in_msg.Dirty; 1516 } 1517 1518 } 1519 } 1520 1521 action(gg_deallocateL1CacheBlock, "\g", desc="Deallocate cache block. Sets the cache to invalid, allowing a replacement in parallel with a fetch.") { 1522 assert(getTokens(cache_entry) == 0); 1523 if (L1Dcache.isTagPresent(address)) { 1524 L1Dcache.deallocate(address); 1525 } else { 1526 L1Icache.deallocate(address); 1527 } 1528 unset_cache_entry(); 1529 } 1530 1531 action(ii_allocateL1DCacheBlock, "\i", desc="Set L1 D-cache tag equal to tag of block B.") { 1532 if (is_valid(cache_entry)) { 1533 } else { 1534 set_cache_entry(L1Dcache.allocate(address, new Entry)); 1535 } 1536 } 1537 1538 action(pp_allocateL1ICacheBlock, "\p", desc="Set L1 I-cache tag equal to tag of block B.") { 1539 if (is_valid(cache_entry)) { 1540 } else { 1541 set_cache_entry(L1Icache.allocate(address, new Entry)); 1542 } 1543 } 1544 1545 action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") { 1546 if (send_evictions) { 1547 DPRINTF(RubySlicc, "Sending invalidation for %#x to the CPU\n", address); 1548 sequencer.evictionCallback(address); 1549 } 1550 } 1551 1552 action(uu_profileInstMiss, "\uim", desc="Profile the demand miss") { 1553 ++L1Icache.demand_misses; 1554 } 1555 1556 action(uu_profileInstHit, "\uih", desc="Profile the demand hit") { 1557 ++L1Icache.demand_hits; 1558 } 1559 1560 action(uu_profileDataMiss, "\udm", desc="Profile the demand miss") { 1561 ++L1Dcache.demand_misses; 1562 } 1563 1564 action(uu_profileDataHit, "\udh", desc="Profile the demand hit") { 1565 ++L1Dcache.demand_hits; 1566 } 1567 1568 action(w_assertIncomingDataAndCacheDataMatch, "w", desc="Assert that the incoming data and the data in the cache match") { 1569 peek(responseNetwork_in, ResponseMsg) { 1570 assert(is_valid(cache_entry)); 1571 assert(cache_entry.DataBlk == in_msg.DataBlk); 1572 } 1573 } 1574 1575 action(zz_stallAndWaitMandatoryQueue, "\z", desc="Send the head of the mandatory queue to the back of the queue.") { 1576 peek(mandatoryQueue_in, RubyRequest) { 1577 APPEND_TRANSITION_COMMENT(in_msg.LineAddress); 1578 } 1579 stall_and_wait(mandatoryQueue_in, address); 1580 } 1581 1582 action(kd_wakeUpDependents, "kd", desc="wake-up dependents") { 1583 wakeUpBuffers(address); 1584 } 1585 1586 action(ka_wakeUpAllDependents, "ka", desc="wake-up all dependents") { 1587 wakeUpAllBuffers(); 1588 } 1589 1590 //***************************************************** 1591 // TRANSITIONS 1592 //***************************************************** 1593 1594 // Transitions for Load/Store/L2_Replacement from transient states 1595 transition({IM, SM, OM, IS, IM_L, IS_L, I_L, S_L, SM_L, M_W, MM_W}, L1_Replacement) { 1596 ta_traceStalledAddress; 1597 zz_stallAndWaitMandatoryQueue; 1598 } 1599 1600 transition({IM, SM, OM, IS, IM_L, IS_L, SM_L}, {Store, Atomic}) { 1601 zz_stallAndWaitMandatoryQueue; 1602 } 1603 1604 transition({IM, IS, IM_L, IS_L}, {Load, Ifetch}) { 1605 zz_stallAndWaitMandatoryQueue; 1606 } 1607 1608 // Lockdowns 1609 transition({NP, I, S, O, M, MM, M_W, MM_W, IM, SM, OM, IS}, Own_Lock_or_Unlock) { 1610 l_popPersistentQueue; 1611 } 1612 1613 // Transitions from NP 1614 transition(NP, Load, IS) { 1615 ii_allocateL1DCacheBlock; 1616 i_allocateTBE; 1617 a_issueReadRequest; 1618 uu_profileDataMiss; 1619 k_popMandatoryQueue; 1620 } 1621 1622 transition(NP, Ifetch, IS) { 1623 pp_allocateL1ICacheBlock; 1624 i_allocateTBE; 1625 a_issueReadRequest; 1626 uu_profileInstMiss; 1627 k_popMandatoryQueue; 1628 } 1629 1630 transition(NP, {Store, Atomic}, IM) { 1631 ii_allocateL1DCacheBlock; 1632 i_allocateTBE; 1633 b_issueWriteRequest; 1634 uu_profileDataMiss; 1635 k_popMandatoryQueue; 1636 } 1637 1638 transition(NP, {Ack, Data_Shared, Data_Owner, Data_All_Tokens}) { 1639 bb_bounceResponse; 1640 n_popResponseQueue; 1641 } 1642 1643 transition(NP, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { 1644 m_popRequestQueue; 1645 } 1646 1647 transition(NP, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, I_L) { 1648 l_popPersistentQueue; 1649 } 1650 1651 // Transitions from Idle 1652 transition(I, Load, IS) { 1653 i_allocateTBE; 1654 a_issueReadRequest; 1655 uu_profileDataMiss; 1656 k_popMandatoryQueue; 1657 } 1658 1659 transition(I, Ifetch, IS) { 1660 i_allocateTBE; 1661 a_issueReadRequest; 1662 uu_profileInstMiss; 1663 k_popMandatoryQueue; 1664 } 1665 1666 transition(I, {Store, Atomic}, IM) { 1667 i_allocateTBE; 1668 b_issueWriteRequest; 1669 uu_profileDataMiss; 1670 k_popMandatoryQueue; 1671 } 1672 1673 transition(I, L1_Replacement) { 1674 ta_traceStalledAddress; 1675 tr_tokenReplacement; 1676 gg_deallocateL1CacheBlock; 1677 ka_wakeUpAllDependents; 1678 } 1679 1680 transition(I, {Transient_GETX, Transient_Local_GETX}) { 1681 t_sendAckWithCollectedTokens; 1682 m_popRequestQueue; 1683 } 1684 1685 transition(I, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) { 1686 m_popRequestQueue; 1687 } 1688 1689 transition(I, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, I_L) { 1690 e_sendAckWithCollectedTokens; 1691 l_popPersistentQueue; 1692 } 1693 1694 transition(I_L, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}) { 1695 l_popPersistentQueue; 1696 } 1697 1698 transition(I, Ack) { 1699 q_updateTokensFromResponse; 1700 n_popResponseQueue; 1701 } 1702 1703 transition(I, Data_Shared, S) { 1704 u_writeDataToCache; 1705 q_updateTokensFromResponse; 1706 n_popResponseQueue; 1707 } 1708 1709 transition(I, Data_Owner, O) { 1710 u_writeDataToCache; 1711 q_updateTokensFromResponse; 1712 n_popResponseQueue; 1713 } 1714 1715 transition(I, Data_All_Tokens, M) { 1716 u_writeDataToCache; 1717 q_updateTokensFromResponse; 1718 n_popResponseQueue; 1719 } 1720 1721 // Transitions from Shared 1722 transition({S, SM, S_L, SM_L}, Load) { 1723 h_load_hit; 1724 uu_profileDataHit; 1725 k_popMandatoryQueue; 1726 } 1727 1728 transition({S, SM, S_L, SM_L}, Ifetch) { 1729 h_ifetch_hit; 1730 uu_profileInstHit; 1731 k_popMandatoryQueue; 1732 } 1733 1734 transition(S, {Store, Atomic}, SM) { 1735 i_allocateTBE; 1736 b_issueWriteRequest; 1737 uu_profileDataMiss; 1738 k_popMandatoryQueue; 1739 } 1740 1741 transition(S, L1_Replacement, I) { 1742 ta_traceStalledAddress; 1743 cc_sharedReplacement; // Only needed in some cases 1744 forward_eviction_to_cpu; 1745 gg_deallocateL1CacheBlock; 1746 ka_wakeUpAllDependents; 1747 } 1748 1749 transition(S, {Transient_GETX, Transient_Local_GETX}, I) { 1750 t_sendAckWithCollectedTokens; 1751 p_informL2AboutTokenLoss; 1752 forward_eviction_to_cpu 1753 m_popRequestQueue; 1754 } 1755 1756 // only owner responds to non-local requests 1757 transition(S, Transient_GETS) { 1758 m_popRequestQueue; 1759 } 1760 1761 transition(S, Transient_Local_GETS) { 1762 d_sendDataWithToken; 1763 m_popRequestQueue; 1764 } 1765 1766 transition(S, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) { 1767 m_popRequestQueue; 1768 } 1769 1770 transition({S, S_L}, Persistent_GETX, I_L) { 1771 e_sendAckWithCollectedTokens; 1772 p_informL2AboutTokenLoss; 1773 forward_eviction_to_cpu 1774 l_popPersistentQueue; 1775 } 1776 1777 transition(S, {Persistent_GETS, Persistent_GETS_Last_Token}, S_L) { 1778 f_sendAckWithAllButNorOneTokens; 1779 l_popPersistentQueue; 1780 } 1781 1782 transition(S_L, {Persistent_GETS, Persistent_GETS_Last_Token}) { 1783 l_popPersistentQueue; 1784 } 1785 1786 transition(S, Ack) { 1787 q_updateTokensFromResponse; 1788 n_popResponseQueue; 1789 } 1790 1791 transition(S, Data_Shared) { 1792 w_assertIncomingDataAndCacheDataMatch; 1793 q_updateTokensFromResponse; 1794 n_popResponseQueue; 1795 } 1796 1797 transition(S, Data_Owner, O) { 1798 w_assertIncomingDataAndCacheDataMatch; 1799 q_updateTokensFromResponse; 1800 n_popResponseQueue; 1801 } 1802 1803 transition(S, Data_All_Tokens, M) { 1804 w_assertIncomingDataAndCacheDataMatch; 1805 q_updateTokensFromResponse; 1806 n_popResponseQueue; 1807 } 1808 1809 // Transitions from Owned 1810 transition({O, OM}, Ifetch) { 1811 h_ifetch_hit; 1812 uu_profileInstHit; 1813 k_popMandatoryQueue; 1814 } 1815 1816 transition({O, OM}, Load) { 1817 h_load_hit; 1818 uu_profileDataHit; 1819 k_popMandatoryQueue; 1820 } 1821 1822 transition(O, {Store, Atomic}, OM) { 1823 i_allocateTBE; 1824 b_issueWriteRequest; 1825 uu_profileDataMiss; 1826 k_popMandatoryQueue; 1827 } 1828 1829 transition(O, L1_Replacement, I) { 1830 ta_traceStalledAddress; 1831 c_ownedReplacement; 1832 forward_eviction_to_cpu 1833 gg_deallocateL1CacheBlock; 1834 ka_wakeUpAllDependents; 1835 } 1836 1837 transition(O, {Transient_GETX, Transient_Local_GETX}, I) { 1838 dd_sendDataWithAllTokens; 1839 p_informL2AboutTokenLoss; 1840 forward_eviction_to_cpu 1841 m_popRequestQueue; 1842 } 1843 1844 transition(O, Persistent_GETX, I_L) { 1845 ee_sendDataWithAllTokens; 1846 p_informL2AboutTokenLoss; 1847 forward_eviction_to_cpu 1848 l_popPersistentQueue; 1849 } 1850 1851 transition(O, Persistent_GETS, S_L) { 1852 ff_sendDataWithAllButNorOneTokens; 1853 l_popPersistentQueue; 1854 } 1855 1856 transition(O, Persistent_GETS_Last_Token, I_L) { 1857 fo_sendDataWithOwnerToken; 1858 forward_eviction_to_cpu 1859 l_popPersistentQueue; 1860 } 1861 1862 transition(O, Transient_GETS) { 1863 d_sendDataWithToken; 1864 m_popRequestQueue; 1865 } 1866 1867 transition(O, Transient_Local_GETS) { 1868 d_sendDataWithToken; 1869 m_popRequestQueue; 1870 } 1871 1872 // ran out of tokens, wait for it to go persistent 1873 transition(O, {Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token}) { 1874 m_popRequestQueue; 1875 } 1876 1877 transition(O, Ack) { 1878 q_updateTokensFromResponse; 1879 n_popResponseQueue; 1880 } 1881 1882 transition(O, Ack_All_Tokens, M) { 1883 q_updateTokensFromResponse; 1884 n_popResponseQueue; 1885 } 1886 1887 transition(O, Data_Shared) { 1888 w_assertIncomingDataAndCacheDataMatch; 1889 q_updateTokensFromResponse; 1890 n_popResponseQueue; 1891 } 1892 1893 transition(O, Data_All_Tokens, M) { 1894 w_assertIncomingDataAndCacheDataMatch; 1895 q_updateTokensFromResponse; 1896 n_popResponseQueue; 1897 } 1898 1899 // Transitions from Modified 1900 transition({MM, MM_W}, Ifetch) { 1901 h_ifetch_hit; 1902 uu_profileInstHit; 1903 k_popMandatoryQueue; 1904 } 1905 1906 transition({MM, MM_W}, Load) { 1907 h_load_hit; 1908 uu_profileDataHit; 1909 k_popMandatoryQueue; 1910 } 1911 1912 transition({MM_W}, {Store, Atomic}) { 1913 hh_store_hit; 1914 uu_profileDataHit; 1915 k_popMandatoryQueue; 1916 } 1917 1918 transition(MM, Store) { 1919 hh_store_hit; 1920 uu_profileDataHit; 1921 k_popMandatoryQueue; 1922 } 1923 1924 transition(MM, Atomic, M) { 1925 hh_store_hit; 1926 uu_profileDataHit; 1927 k_popMandatoryQueue; 1928 } 1929 1930 transition(MM, L1_Replacement, I) { 1931 ta_traceStalledAddress; 1932 c_ownedReplacement; 1933 forward_eviction_to_cpu 1934 gg_deallocateL1CacheBlock; 1935 ka_wakeUpAllDependents; 1936 } 1937 1938 transition(MM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}, I) { 1939 dd_sendDataWithAllTokens; 1940 p_informL2AboutTokenLoss; 1941 forward_eviction_to_cpu 1942 m_popRequestQueue; 1943 } 1944 1945 transition({MM_W}, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request 1946 m_popRequestQueue; 1947 } 1948 1949 // Implement the migratory sharing optimization, even for persistent requests 1950 transition(MM, {Persistent_GETX, Persistent_GETS}, I_L) { 1951 ee_sendDataWithAllTokens; 1952 p_informL2AboutTokenLoss; 1953 forward_eviction_to_cpu 1954 l_popPersistentQueue; 1955 } 1956 1957 // ignore persistent requests in lockout period 1958 transition(MM_W, {Persistent_GETX, Persistent_GETS}) { 1959 l_popPersistentQueue; 1960 } 1961 1962 transition(MM_W, Use_TimeoutNoStarvers, MM) { 1963 s_deallocateTBE; 1964 jj_unsetUseTimer; 1965 kd_wakeUpDependents; 1966 } 1967 1968 transition(MM_W, Use_TimeoutNoStarvers_NoMig, M) { 1969 s_deallocateTBE; 1970 jj_unsetUseTimer; 1971 kd_wakeUpDependents; 1972 } 1973 1974 // Transitions from Dirty Exclusive 1975 transition({M, M_W}, Ifetch) { 1976 h_ifetch_hit; 1977 uu_profileInstHit; 1978 k_popMandatoryQueue; 1979 } 1980 1981 transition({M, M_W}, Load) { 1982 h_load_hit; 1983 uu_profileDataHit; 1984 k_popMandatoryQueue; 1985 } 1986 1987 transition(M, Store, MM) { 1988 hh_store_hit; 1989 uu_profileDataHit; 1990 k_popMandatoryQueue; 1991 } 1992 1993 transition(M, Atomic) { 1994 hh_store_hit; 1995 uu_profileDataHit; 1996 k_popMandatoryQueue; 1997 } 1998 1999 transition(M_W, Store, MM_W) { 2000 hh_store_hit; 2001 uu_profileDataHit; 2002 k_popMandatoryQueue; 2003 } 2004 2005 transition(M_W, Atomic) { 2006 hh_store_hit; 2007 uu_profileDataHit; 2008 k_popMandatoryQueue; 2009 } 2010 2011 transition(M, L1_Replacement, I) { 2012 ta_traceStalledAddress; 2013 c_ownedReplacement; 2014 forward_eviction_to_cpu 2015 gg_deallocateL1CacheBlock; 2016 ka_wakeUpAllDependents; 2017 } 2018 2019 transition(M, {Transient_GETX, Transient_Local_GETX}, I) { 2020 dd_sendDataWithAllTokens; 2021 p_informL2AboutTokenLoss; 2022 forward_eviction_to_cpu 2023 m_popRequestQueue; 2024 } 2025 2026 transition(M, Transient_Local_GETS, O) { 2027 d_sendDataWithToken; 2028 m_popRequestQueue; 2029 } 2030 2031 transition(M, Transient_GETS, O) { 2032 d_sendDataWithNTokenIfAvail; 2033 m_popRequestQueue; 2034 } 2035 2036 transition(M_W, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}) { // Ignore the request 2037 m_popRequestQueue; 2038 } 2039 2040 transition(M, Persistent_GETX, I_L) { 2041 ee_sendDataWithAllTokens; 2042 p_informL2AboutTokenLoss; 2043 forward_eviction_to_cpu 2044 l_popPersistentQueue; 2045 } 2046 2047 transition(M, Persistent_GETS, S_L) { 2048 ff_sendDataWithAllButNorOneTokens; 2049 l_popPersistentQueue; 2050 } 2051 2052 // ignore persistent requests in lockout period 2053 transition(M_W, {Persistent_GETX, Persistent_GETS}) { 2054 l_popPersistentQueue; 2055 } 2056 2057 transition(M_W, Use_TimeoutStarverS, S_L) { 2058 s_deallocateTBE; 2059 ff_sendDataWithAllButNorOneTokens; 2060 jj_unsetUseTimer; 2061 } 2062 2063 // someone unlocked during timeout 2064 transition(M_W, {Use_TimeoutNoStarvers, Use_TimeoutNoStarvers_NoMig}, M) { 2065 s_deallocateTBE; 2066 jj_unsetUseTimer; 2067 kd_wakeUpDependents; 2068 } 2069 2070 transition(M_W, Use_TimeoutStarverX, I_L) { 2071 s_deallocateTBE; 2072 ee_sendDataWithAllTokens; 2073 forward_eviction_to_cpu; 2074 p_informL2AboutTokenLoss; 2075 jj_unsetUseTimer; 2076 } 2077 2078 // migratory 2079 transition(MM_W, {Use_TimeoutStarverX, Use_TimeoutStarverS}, I_L) { 2080 s_deallocateTBE; 2081 ee_sendDataWithAllTokens; 2082 forward_eviction_to_cpu; 2083 p_informL2AboutTokenLoss; 2084 jj_unsetUseTimer; 2085 2086 } 2087 2088 // Transient_GETX and Transient_GETS in transient states 2089 transition(OM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) { 2090 m_popRequestQueue; // Even if we have the data, we can pretend we don't have it yet. 2091 } 2092 2093 transition(IS, {Transient_GETX, Transient_Local_GETX}) { 2094 t_sendAckWithCollectedTokens; 2095 m_popRequestQueue; 2096 } 2097 2098 transition(IS, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) { 2099 m_popRequestQueue; 2100 } 2101 2102 transition(IS, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, IS_L) { 2103 e_sendAckWithCollectedTokens; 2104 l_popPersistentQueue; 2105 } 2106 2107 transition(IS_L, {Persistent_GETX, Persistent_GETS}) { 2108 l_popPersistentQueue; 2109 } 2110 2111 transition(IM, {Persistent_GETX, Persistent_GETS, Persistent_GETS_Last_Token}, IM_L) { 2112 e_sendAckWithCollectedTokens; 2113 l_popPersistentQueue; 2114 } 2115 2116 transition(IM_L, {Persistent_GETX, Persistent_GETS}) { 2117 l_popPersistentQueue; 2118 } 2119 2120 transition({SM, SM_L}, Persistent_GETX, IM_L) { 2121 e_sendAckWithCollectedTokens; 2122 forward_eviction_to_cpu 2123 l_popPersistentQueue; 2124 } 2125 2126 transition(SM, {Persistent_GETS, Persistent_GETS_Last_Token}, SM_L) { 2127 f_sendAckWithAllButNorOneTokens; 2128 l_popPersistentQueue; 2129 } 2130 2131 transition(SM_L, {Persistent_GETS, Persistent_GETS_Last_Token}) { 2132 l_popPersistentQueue; 2133 } 2134 2135 transition(OM, Persistent_GETX, IM_L) { 2136 ee_sendDataWithAllTokens; 2137 forward_eviction_to_cpu 2138 l_popPersistentQueue; 2139 } 2140 2141 transition(OM, Persistent_GETS, SM_L) { 2142 ff_sendDataWithAllButNorOneTokens; 2143 l_popPersistentQueue; 2144 } 2145 2146 transition(OM, Persistent_GETS_Last_Token, IM_L) { 2147 fo_sendDataWithOwnerToken; 2148 l_popPersistentQueue; 2149 } 2150 2151 // Transitions from IM/SM 2152 2153 transition({IM, SM}, Ack) { 2154 q_updateTokensFromResponse; 2155 n_popResponseQueue; 2156 } 2157 2158 transition(IM, Data_Shared, SM) { 2159 u_writeDataToCache; 2160 q_updateTokensFromResponse; 2161 n_popResponseQueue; 2162 } 2163 2164 transition(IM, Data_Owner, OM) { 2165 u_writeDataToCache; 2166 q_updateTokensFromResponse; 2167 n_popResponseQueue; 2168 } 2169 2170 transition(IM, Data_All_Tokens, MM_W) { 2171 u_writeDataToCache; 2172 q_updateTokensFromResponse; 2173 xx_external_store_hit; 2174 o_scheduleUseTimeout; 2175 j_unsetReissueTimer; 2176 n_popResponseQueue; 2177 kd_wakeUpDependents; 2178 } 2179 2180 transition(SM, Data_Shared) { 2181 w_assertIncomingDataAndCacheDataMatch; 2182 q_updateTokensFromResponse; 2183 n_popResponseQueue; 2184 } 2185 2186 transition(SM, Data_Owner, OM) { 2187 w_assertIncomingDataAndCacheDataMatch; 2188 q_updateTokensFromResponse; 2189 n_popResponseQueue; 2190 } 2191 2192 transition(SM, Data_All_Tokens, MM_W) { 2193 w_assertIncomingDataAndCacheDataMatch; 2194 q_updateTokensFromResponse; 2195 xx_external_store_hit; 2196 o_scheduleUseTimeout; 2197 j_unsetReissueTimer; 2198 n_popResponseQueue; 2199 kd_wakeUpDependents; 2200 } 2201 2202 transition({IM, SM}, {Transient_GETX, Transient_Local_GETX}, IM) { // We don't have the data yet, but we might have collected some tokens. We give them up here to avoid livelock 2203 t_sendAckWithCollectedTokens; 2204 forward_eviction_to_cpu; 2205 m_popRequestQueue; 2206 } 2207 2208 transition({IM, SM}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) { 2209 m_popRequestQueue; 2210 } 2211 2212 transition({IM, SM}, Request_Timeout) { 2213 j_unsetReissueTimer; 2214 b_issueWriteRequest; 2215 } 2216 2217 // Transitions from OM 2218 2219 transition(OM, Ack) { 2220 q_updateTokensFromResponse; 2221 n_popResponseQueue; 2222 } 2223 2224 transition(OM, Ack_All_Tokens, MM_W) { 2225 q_updateTokensFromResponse; 2226 xx_external_store_hit; 2227 o_scheduleUseTimeout; 2228 j_unsetReissueTimer; 2229 n_popResponseQueue; 2230 kd_wakeUpDependents; 2231 } 2232 2233 transition(OM, Data_Shared) { 2234 w_assertIncomingDataAndCacheDataMatch; 2235 q_updateTokensFromResponse; 2236 n_popResponseQueue; 2237 } 2238 2239 transition(OM, Data_All_Tokens, MM_W) { 2240 w_assertIncomingDataAndCacheDataMatch; 2241 q_updateTokensFromResponse; 2242 xx_external_store_hit; 2243 o_scheduleUseTimeout; 2244 j_unsetReissueTimer; 2245 n_popResponseQueue; 2246 kd_wakeUpDependents; 2247 } 2248 2249 transition(OM, Request_Timeout) { 2250 j_unsetReissueTimer; 2251 b_issueWriteRequest; 2252 } 2253 2254 // Transitions from IS 2255 2256 transition(IS, Ack) { 2257 q_updateTokensFromResponse; 2258 n_popResponseQueue; 2259 } 2260 2261 transition(IS, Data_Shared, S) { 2262 u_writeDataToCache; 2263 q_updateTokensFromResponse; 2264 x_external_load_hit; 2265 s_deallocateTBE; 2266 j_unsetReissueTimer; 2267 n_popResponseQueue; 2268 kd_wakeUpDependents; 2269 } 2270 2271 transition(IS, Data_Owner, O) { 2272 u_writeDataToCache; 2273 q_updateTokensFromResponse; 2274 x_external_load_hit; 2275 s_deallocateTBE; 2276 j_unsetReissueTimer; 2277 n_popResponseQueue; 2278 kd_wakeUpDependents; 2279 } 2280 2281 transition(IS, Data_All_Tokens, M_W) { 2282 u_writeDataToCache; 2283 q_updateTokensFromResponse; 2284 x_external_load_hit; 2285 o_scheduleUseTimeout; 2286 j_unsetReissueTimer; 2287 n_popResponseQueue; 2288 kd_wakeUpDependents; 2289 } 2290 2291 transition(IS, Request_Timeout) { 2292 j_unsetReissueTimer; 2293 a_issueReadRequest; 2294 } 2295 2296 // Transitions from I_L 2297 2298 transition(I_L, Load, IS_L) { 2299 ii_allocateL1DCacheBlock; 2300 i_allocateTBE; 2301 a_issueReadRequest; 2302 uu_profileDataMiss; 2303 k_popMandatoryQueue; 2304 } 2305 2306 transition(I_L, Ifetch, IS_L) { 2307 pp_allocateL1ICacheBlock; 2308 i_allocateTBE; 2309 a_issueReadRequest; 2310 uu_profileInstMiss; 2311 k_popMandatoryQueue; 2312 } 2313 2314 transition(I_L, {Store, Atomic}, IM_L) { 2315 ii_allocateL1DCacheBlock; 2316 i_allocateTBE; 2317 b_issueWriteRequest; 2318 uu_profileDataMiss; 2319 k_popMandatoryQueue; 2320 } 2321 2322 2323 // Transitions from S_L 2324 2325 transition(S_L, {Store, Atomic}, SM_L) { 2326 i_allocateTBE; 2327 b_issueWriteRequest; 2328 uu_profileDataMiss; 2329 k_popMandatoryQueue; 2330 } 2331 2332 // Other transitions from *_L states 2333 2334 transition({I_L, IM_L, IS_L, S_L, SM_L}, {Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS, Transient_GETX, Transient_Local_GETX}) { 2335 m_popRequestQueue; 2336 } 2337 2338 transition({I_L, IM_L, IS_L, S_L, SM_L}, Ack) { 2339 g_bounceResponseToStarver; 2340 n_popResponseQueue; 2341 } 2342 2343 transition({I_L, IM_L, S_L, SM_L}, {Data_Shared, Data_Owner}) { 2344 g_bounceResponseToStarver; 2345 n_popResponseQueue; 2346 } 2347 2348 transition({I_L, S_L}, Data_All_Tokens) { 2349 g_bounceResponseToStarver; 2350 n_popResponseQueue; 2351 } 2352 2353 transition(IS_L, Request_Timeout) { 2354 j_unsetReissueTimer; 2355 a_issueReadRequest; 2356 } 2357 2358 transition({IM_L, SM_L}, Request_Timeout) { 2359 j_unsetReissueTimer; 2360 b_issueWriteRequest; 2361 } 2362 2363 // Opportunisticly Complete the memory operation in the following 2364 // cases. Note: these transitions could just use 2365 // g_bounceResponseToStarver, but if we have the data and tokens, we 2366 // might as well complete the memory request while we have the 2367 // chance (and then immediately forward on the data) 2368 2369 transition(IM_L, Data_All_Tokens, MM_W) { 2370 u_writeDataToCache; 2371 q_updateTokensFromResponse; 2372 xx_external_store_hit; 2373 j_unsetReissueTimer; 2374 o_scheduleUseTimeout; 2375 n_popResponseQueue; 2376 kd_wakeUpDependents; 2377 } 2378 2379 transition(SM_L, Data_All_Tokens, S_L) { 2380 u_writeDataToCache; 2381 q_updateTokensFromResponse; 2382 xx_external_store_hit; 2383 ff_sendDataWithAllButNorOneTokens; 2384 s_deallocateTBE; 2385 j_unsetReissueTimer; 2386 n_popResponseQueue; 2387 } 2388 2389 transition(IS_L, Data_Shared, I_L) { 2390 u_writeDataToCache; 2391 q_updateTokensFromResponse; 2392 x_external_load_hit; 2393 s_deallocateTBE; 2394 e_sendAckWithCollectedTokens; 2395 p_informL2AboutTokenLoss; 2396 j_unsetReissueTimer; 2397 n_popResponseQueue; 2398 } 2399 2400 transition(IS_L, Data_Owner, I_L) { 2401 u_writeDataToCache; 2402 q_updateTokensFromResponse; 2403 x_external_load_hit; 2404 ee_sendDataWithAllTokens; 2405 s_deallocateTBE; 2406 p_informL2AboutTokenLoss; 2407 j_unsetReissueTimer; 2408 n_popResponseQueue; 2409 } 2410 2411 transition(IS_L, Data_All_Tokens, M_W) { 2412 u_writeDataToCache; 2413 q_updateTokensFromResponse; 2414 x_external_load_hit; 2415 j_unsetReissueTimer; 2416 o_scheduleUseTimeout; 2417 n_popResponseQueue; 2418 kd_wakeUpDependents; 2419 } 2420 2421 // Own_Lock_or_Unlock 2422 2423 transition(I_L, Own_Lock_or_Unlock, I) { 2424 l_popPersistentQueue; 2425 kd_wakeUpDependents; 2426 } 2427 2428 transition(S_L, Own_Lock_or_Unlock, S) { 2429 l_popPersistentQueue; 2430 kd_wakeUpDependents; 2431 } 2432 2433 transition(IM_L, Own_Lock_or_Unlock, IM) { 2434 l_popPersistentQueue; 2435 kd_wakeUpDependents; 2436 } 2437 2438 transition(IS_L, Own_Lock_or_Unlock, IS) { 2439 l_popPersistentQueue; 2440 kd_wakeUpDependents; 2441 } 2442 2443 transition(SM_L, Own_Lock_or_Unlock, SM) { 2444 l_popPersistentQueue; 2445 kd_wakeUpDependents; 2446 } 2447} 2448