1/* 2 * Copyright (c) 2010-2015 Advanced Micro Devices, Inc. 3 * All rights reserved. 4 * 5 * For use for simulation and test purposes only 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright notice, 14 * this list of conditions and the following disclaimer in the documentation 15 * and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the copyright holder nor the names of its 18 * contributors may be used to endorse or promote products derived from this 19 * software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 * Authors: Jason Power 34 */ 35 36machine(MachineType:RegionBuffer, "Region Buffer for AMD_Base-like protocol") 37: CacheMemory *cacheMemory; // stores only region addresses. Must set block size same as below 38 bool isOnCPU; 39 int blocksPerRegion := 64; // 4k regions 40 Cycles toDirLatency := 5; // Latency to fwd requests to directory 41 Cycles toRegionDirLatency := 5; // Latency for requests and acks to directory 42 Cycles nextEvictLatency := 1; // latency added between each block while evicting region 43 bool noTCCdir := "False"; 44 int TCC_select_num_bits := 1; 45 46 // From the Cores 47 MessageBuffer * requestFromCore, network="From", virtual_network="0", vnet_type="request"; 48 MessageBuffer * responseFromCore, network="From", virtual_network="2", vnet_type="response"; 49 50 // Requests to the cores or directory 51 MessageBuffer * requestToNetwork, network="To", virtual_network="0", vnet_type="request"; 52 53 // From Region-Dir 54 MessageBuffer * notifyFromRegionDir, network="From", virtual_network="7", vnet_type="request"; 55 MessageBuffer * probeFromRegionDir, network="From", virtual_network="8", vnet_type="request"; 56 57 // From the directory 58 MessageBuffer * unblockFromDir, network="From", virtual_network="4", vnet_type="unblock"; 59 60 // To the region-Dir 61 MessageBuffer * responseToRegDir, network="To", virtual_network="2", vnet_type="response"; 62 63 MessageBuffer * triggerQueue; 64{ 65 66 // States 67 state_declaration(State, desc="Region states", default="RegionBuffer_State_NP") { 68 NP, AccessPermission:Invalid, desc="Not present in region directory"; 69 P, AccessPermission:Invalid, desc="Region is private to the cache"; 70 S, AccessPermission:Invalid, desc="Region is possibly shared with others"; 71 72 NP_PS, AccessPermission:Invalid, desc="Intermediate state waiting for notify from r-dir"; 73 S_P, AccessPermission:Invalid, desc="Intermediate state while upgrading region"; 74 75 P_NP, AccessPermission:Invalid, desc="Intermediate state while evicting all lines in region"; 76 P_S, AccessPermission:Invalid, desc="Intermediate state while downgrading all lines in region"; 77 78 S_NP_PS, AccessPermission:Invalid, desc="Got an inv in S_P, waiting for all inv acks, then going to since the write is already out there NP_PS"; 79 P_NP_NP, AccessPermission:Invalid, desc="Evicting region on repl, then got an inv. Need to re-evict"; 80 81 P_NP_O, AccessPermission:Invalid, desc="Waiting for all outstanding requests"; 82 P_S_O, AccessPermission:Invalid, desc="Waiting for all outstanding requests"; 83 S_O, AccessPermission:Invalid, desc="Waiting for all outstanding requests"; 84 S_NP_PS_O, AccessPermission:Invalid, desc="Waiting for all outstanding requests"; 85 86 SS_P, AccessPermission:Invalid, desc="Waiting for CPU write that we know is there"; 87 88 P_NP_W, AccessPermission:Invalid, desc="Waiting for writeback ack"; 89 90 NP_W, AccessPermission:Invalid, desc="Got a done ack before request, waiting for that victim"; 91 } 92 93 enumeration(Event, desc="Region directory events") { 94 CPURead, desc="Access from CPU core"; 95 CPUWrite, desc="Access from CPU core"; 96 CPUWriteback, desc="Writeback request from CPU core"; 97 98 ReplRegion, desc="Start a replace on a region"; 99 100 PrivateNotify, desc="Update entry to private state"; 101 SharedNotify, desc="Update entry to shared state"; 102 WbNotify, desc="Writeback notification received"; 103 InvRegion, desc="Start invalidating a region"; 104 DowngradeRegion,desc="Start invalidating a region"; 105 106 InvAck, desc="Ack from core"; 107 108 DoneAck, desc="Ack from core that request has finished"; 109 AllOutstanding, desc="All outstanding requests have now finished"; 110 111 Evict, desc="Loopback to evict each block"; 112 LastAck_PrbResp, desc="Done eviciting all the blocks, got the last ack from core, now respond to region dir"; 113 LastAck_CleanWb, desc="Done eviciting all the blocks, got the last ack from core, now start clean writeback (note the dir has already been updated)"; 114 115 StallAccess, desc="Wait for the done ack on the address before proceeding"; 116 StallDoneAck, desc="Wait for the access on the address before proceeding"; 117 118 StaleRequest, desc="Got a stale victim from the cache, fwd it without incrementing outstanding"; 119 } 120 121 enumeration(RequestType, desc="To communicate stats from transitions to recordStats") { 122 TagArrayRead, desc="Read the data array"; 123 TagArrayWrite, desc="Write the data array"; 124 } 125 126 structure(BoolVec, external="yes") { 127 bool at(int); 128 void resize(int); 129 void clear(); 130 int size(); 131 } 132 133 structure(Entry, desc="Region entry", interface="AbstractCacheEntry") { 134 Addr addr, desc="Base address of this region"; 135 State RegionState, desc="Region state"; 136 DataBlock DataBlk, desc="Data for the block (always empty in region buffer)"; 137 BoolVec ValidBlocks, desc="A vector to keep track of valid blocks"; 138 int NumValidBlocks, desc="Number of trues in ValidBlocks to avoid iterating"; 139 BoolVec UsedBlocks, desc="A vector to keep track of blocks ever valid"; 140 bool dirty, desc="Dirty as best known by the region buffer"; 141 // This is needed so we don't ack an invalidate until all requests are ordered 142 int NumOutstandingReqs, desc="Total outstanding private/shared requests"; 143 BoolVec OutstandingReqs, desc="Blocks that have outstanding private/shared requests"; 144 bool MustDowngrade, desc="Set when we got a downgrade before the shd or pvt permissions"; 145 Cycles ProbeRequestTime, default="Cycles(0)", desc="Time region dir started the probe"; 146 Cycles InitialRequestTime, default="Cycles(0)", desc="Time message was sent to region dir"; 147 bool MsgSentToDir, desc="True if the current request required a message to the dir"; 148 bool clearOnDone, default="false", desc="clear valid bit when request completes"; 149 Addr clearOnDoneAddr, desc="clear valid bit when request completes"; 150 } 151 152 structure(TBE, desc="...") { 153 State TBEState, desc="Transient state"; 154 //int NumValidBlocks, desc="Number of blocks valid so we don't have to count a BoolVec"; 155 BoolVec ValidBlocks, desc="A vector to keep track of valid blocks"; 156 bool AllAcksReceived, desc="Got all necessary acks from dir"; 157 bool DoneEvicting, desc="Done iterating through blocks checking for valids"; 158 BoolVec AcksReceived, desc="Received acks for theses blocks\n"; 159 bool SendAck, desc="If true, send an ack to the r-dir at end of inv"; 160 ProbeRequestType MsgType, desc="Type of message to send while 'evicting' "; 161 int NumOutstandingReqs, desc="Total outstanding private/shared requests"; 162 BoolVec OutstandingReqs, desc="Blocks that have outstanding private/shared requests"; 163 MachineID Requestor, desc="Requestor for three hop transactions"; 164 bool DemandRequest, default="false", desc="Associated with a demand request"; 165 Addr DemandAddress, desc="Address for the demand request"; 166 bool DoneAckReceived, default="false", desc="True if the done ack arrived before the message"; 167 Addr DoneAckAddr, desc="Address of the done ack received early"; 168 int OutstandingThreshold, desc="Number of outstanding requests to trigger AllOutstanding on"; 169 170 ProbeRequestType NewMsgType, desc="Type of message to send while 'evicting' "; 171 MachineID NewRequestor, desc="Requestor for three hop transactions"; 172 bool NewDemandRequest, default="false", desc="Associated with a demand request"; 173 Addr NewDemandAddress, desc="Address for the demand request"; 174 bool dirty, desc="dirty"; 175 bool AllOutstandingTriggered, default="false", desc="bit for only one all outstanding"; 176 int OutstandingAcks, default="0", desc="number of acks to wait for"; 177 } 178 179 structure(TBETable, external="yes") { 180 TBE lookup(Addr); 181 void allocate(Addr); 182 void deallocate(Addr); 183 bool isPresent(Addr); 184 } 185 186 // Stores only region addresses 187 TBETable TBEs, template="<RegionBuffer_TBE>", constructor="m_number_of_TBEs"; 188 int TCC_select_low_bit, default="RubySystem::getBlockSizeBits()"; 189 190 Tick clockEdge(); 191 Tick cyclesToTicks(Cycles c); 192 193 void set_cache_entry(AbstractCacheEntry b); 194 void unset_cache_entry(); 195 void set_tbe(TBE b); 196 void unset_tbe(); 197 void wakeUpAllBuffers(); 198 void wakeUpBuffers(Addr a); 199 Cycles curCycle(); 200 MachineID mapAddressToMachine(Addr addr, MachineType mtype); 201 202 int blockBits, default="RubySystem::getBlockSizeBits()"; 203 int blockBytes, default="RubySystem::getBlockSizeBytes()"; 204 int regionBits, default="log2(m_blocksPerRegion)"; 205 206 // Functions 207 208 int getRegionOffset(Addr addr) { 209 if (blocksPerRegion > 1) { 210 Addr offset := bitSelect(addr, blockBits, regionBits+blockBits-1); 211 int ret := addressToInt(offset); 212 assert(ret < blocksPerRegion); 213 return ret; 214 } else { 215 return 0; 216 } 217 } 218 219 Addr getRegionBase(Addr addr) { 220 return maskLowOrderBits(addr, blockBits+regionBits); 221 } 222 223 Addr getNextBlock(Addr addr) { 224 Addr a := addr; 225 return makeNextStrideAddress(a, 1); 226 } 227 228 MachineID getPeer(MachineID mach, Addr address) { 229 if (isOnCPU) { 230 return createMachineID(MachineType:CorePair, intToID(0)); 231 } else if (noTCCdir) { 232 return mapAddressToRange(address,MachineType:TCC, 233 TCC_select_low_bit, TCC_select_num_bits); 234 } else { 235 return createMachineID(MachineType:TCCdir, intToID(0)); 236 } 237 } 238 239 bool isOutstanding(TBE tbe, Entry cache_entry, Addr addr) { 240 if (is_valid(tbe) && tbe.OutstandingReqs.size() > 0) { 241 DPRINTF(RubySlicc, " outstanding tbe reqs %s %s %d %d\n", 242 tbe.OutstandingReqs, addr, getRegionOffset(addr), 243 tbe.OutstandingReqs.at(getRegionOffset(addr))); 244 return tbe.OutstandingReqs.at(getRegionOffset(addr)); 245 } else if (is_valid(cache_entry)) { 246 DPRINTF(RubySlicc, " outstanding cache reqs %s %s %d %d\n", 247 cache_entry.OutstandingReqs, addr, getRegionOffset(addr), 248 cache_entry.OutstandingReqs.at(getRegionOffset(addr))); 249 return cache_entry.OutstandingReqs.at(getRegionOffset(addr)); 250 } else { 251 return false; 252 } 253 } 254 255 bool isOnGPU() { 256 if (isOnCPU) { 257 return false; 258 } 259 return true; 260 } 261 262 bool isRead(CoherenceRequestType type) { 263 return (type == CoherenceRequestType:RdBlk || type == CoherenceRequestType:RdBlkS || 264 type == CoherenceRequestType:VicClean); 265 } 266 267 bool presentOrAvail(Addr addr) { 268 return cacheMemory.isTagPresent(getRegionBase(addr)) || cacheMemory.cacheAvail(getRegionBase(addr)); 269 } 270 271 // Returns a region entry! 272 Entry getCacheEntry(Addr addr), return_by_pointer="yes" { 273 return static_cast(Entry, "pointer", cacheMemory.lookup(getRegionBase(addr))); 274 } 275 276 TBE getTBE(Addr addr), return_by_pointer="yes" { 277 return TBEs.lookup(getRegionBase(addr)); 278 } 279 280 DataBlock getDataBlock(Addr addr), return_by_ref="yes" { 281 return getCacheEntry(getRegionBase(addr)).DataBlk; 282 } 283 284 State getState(TBE tbe, Entry cache_entry, Addr addr) { 285 if (is_valid(tbe)) { 286 return tbe.TBEState; 287 } else if (is_valid(cache_entry)) { 288 return cache_entry.RegionState; 289 } 290 return State:NP; 291 } 292 293 void setState(TBE tbe, Entry cache_entry, Addr addr, State state) { 294 if (is_valid(tbe)) { 295 tbe.TBEState := state; 296 } 297 if (is_valid(cache_entry)) { 298 cache_entry.RegionState := state; 299 } 300 } 301 302 AccessPermission getAccessPermission(Addr addr) { 303 TBE tbe := getTBE(addr); 304 if(is_valid(tbe)) { 305 return RegionBuffer_State_to_permission(tbe.TBEState); 306 } 307 Entry cache_entry := getCacheEntry(addr); 308 if(is_valid(cache_entry)) { 309 return RegionBuffer_State_to_permission(cache_entry.RegionState); 310 } 311 return AccessPermission:NotPresent; 312 } 313 314 void functionalRead(Addr addr, Packet *pkt) { 315 functionalMemoryRead(pkt); 316 } 317 318 int functionalWrite(Addr addr, Packet *pkt) { 319 if (functionalMemoryWrite(pkt)) { 320 return 1; 321 } else { 322 return 0; 323 } 324 } 325 326 void setAccessPermission(Entry cache_entry, Addr addr, State state) { 327 if (is_valid(cache_entry)) { 328 cache_entry.changePermission(RegionBuffer_State_to_permission(state)); 329 } 330 } 331 332 void recordRequestType(RequestType stat, Addr addr) { 333 if (stat == RequestType:TagArrayRead) { 334 cacheMemory.recordRequestType(CacheRequestType:TagArrayRead, addr); 335 } else if (stat == RequestType:TagArrayWrite) { 336 cacheMemory.recordRequestType(CacheRequestType:TagArrayWrite, addr); 337 } 338 } 339 340 bool checkResourceAvailable(RequestType request_type, Addr addr) { 341 if (request_type == RequestType:TagArrayRead) { 342 return cacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr); 343 } else if (request_type == RequestType:TagArrayWrite) { 344 return cacheMemory.checkResourceAvailable(CacheResourceType:TagArray, addr); 345 } else { 346 error("Invalid RequestType type in checkResourceAvailable"); 347 return true; 348 } 349 } 350 351 out_port(triggerQueue_out, TriggerMsg, triggerQueue); 352 353 // Overloaded outgoing request nework for both probes to cores and reqeusts 354 // to the directory. 355 // Fix Me: These forwarded requests need to be on a separate virtual channel 356 // to avoid deadlock! 357 out_port(requestNetwork_out, CPURequestMsg, requestToNetwork); 358 out_port(probeNetwork_out, NBProbeRequestMsg, requestToNetwork); 359 360 out_port(responseNetwork_out, ResponseMsg, responseToRegDir); 361 362 in_port(triggerQueue_in, TriggerMsg, triggerQueue, rank=4) { 363 if (triggerQueue_in.isReady(clockEdge())) { 364 peek(triggerQueue_in, TriggerMsg) { 365 Entry cache_entry := getCacheEntry(in_msg.addr); 366 TBE tbe := getTBE(in_msg.addr); 367 DPRINTF(RubySlicc, "trigger msg: %s (%s)\n", in_msg, getRegionBase(in_msg.addr)); 368 assert(is_valid(tbe)); 369 if (in_msg.Type == TriggerType:AcksComplete) { 370 if (tbe.SendAck) { 371 trigger(Event:LastAck_PrbResp, in_msg.addr, cache_entry, tbe); 372 } else { 373 trigger(Event:LastAck_CleanWb, in_msg.addr, cache_entry, tbe); 374 } 375 } else if (in_msg.Type == TriggerType:AllOutstanding) { 376 trigger(Event:AllOutstanding, in_msg.addr, cache_entry, tbe); 377 } else { 378 assert(in_msg.Type == TriggerType:InvNext); 379 trigger(Event:Evict, in_msg.addr, cache_entry, tbe); 380 } 381 } 382 } 383 } 384 385 in_port(unblockNetwork_in, UnblockMsg, unblockFromDir, rank=3) { 386 if (unblockNetwork_in.isReady(clockEdge())) { 387 peek(unblockNetwork_in, UnblockMsg) { 388 TBE tbe := getTBE(in_msg.addr); 389 Entry cache_entry := getCacheEntry(in_msg.addr); 390 if (in_msg.DoneAck) { 391 if (isOutstanding(tbe, cache_entry, in_msg.addr)) { 392 trigger(Event:DoneAck, in_msg.addr, cache_entry, tbe); 393 } else { 394 trigger(Event:StallDoneAck, in_msg.addr, cache_entry, tbe); 395 } 396 } else { 397 assert(is_valid(tbe)); 398 trigger(Event:InvAck, in_msg.addr, cache_entry, tbe); 399 } 400 } 401 } 402 } 403 404 in_port(probeNetwork_in, NBProbeRequestMsg, probeFromRegionDir, rank=2) { 405 if (probeNetwork_in.isReady(clockEdge())) { 406 peek(probeNetwork_in, NBProbeRequestMsg) { 407 TBE tbe := getTBE(in_msg.addr); 408 Entry cache_entry := getCacheEntry(in_msg.addr); 409 assert(getRegionBase(in_msg.addr) == in_msg.addr); 410 if (in_msg.Type == ProbeRequestType:PrbInv) { 411 trigger(Event:InvRegion, in_msg.addr, cache_entry, tbe); 412 } else if (in_msg.Type == ProbeRequestType:PrbDowngrade) { 413 trigger(Event:DowngradeRegion, in_msg.addr, cache_entry, tbe); 414 } else { 415 error("Unknown probe message\n"); 416 } 417 } 418 } 419 } 420 421 in_port(notifyNetwork_in, CPURequestMsg, notifyFromRegionDir, rank=1) { 422 if (notifyNetwork_in.isReady(clockEdge())) { 423 peek(notifyNetwork_in, CPURequestMsg) { 424 TBE tbe := getTBE(in_msg.addr); 425 Entry cache_entry := getCacheEntry(in_msg.addr); 426 //Fix Me...add back in: assert(is_valid(cache_entry)); 427 if (in_msg.Type == CoherenceRequestType:WbNotify) { 428 trigger(Event:WbNotify, in_msg.addr, cache_entry, tbe); 429 } else if (in_msg.Type == CoherenceRequestType:SharedNotify) { 430 trigger(Event:SharedNotify, in_msg.addr, cache_entry, tbe); 431 } else if (in_msg.Type == CoherenceRequestType:PrivateNotify) { 432 trigger(Event:PrivateNotify, in_msg.addr, cache_entry, tbe); 433 } else { 434 error("Unknown notify message\n"); 435 } 436 } 437 } 438 } 439 440 // In from cores 441 // NOTE: We get the cache / TBE entry based on the region address, 442 // but pass the block address to the actions 443 in_port(requestNetwork_in, CPURequestMsg, requestFromCore, rank=0) { 444 if (requestNetwork_in.isReady(clockEdge())) { 445 peek(requestNetwork_in, CPURequestMsg) { 446 TBE tbe := getTBE(in_msg.addr); 447 Entry cache_entry := getCacheEntry(in_msg.addr); 448 if (is_valid(tbe) && tbe.DoneAckReceived && tbe.DoneAckAddr == in_msg.addr) { 449 DPRINTF(RubySlicc, "Stale/Stall request %s\n", in_msg.Type); 450 if (in_msg.Type == CoherenceRequestType:VicDirty || in_msg.Type == CoherenceRequestType:VicClean ) 451 { 452 trigger(Event:StaleRequest, in_msg.addr, cache_entry, tbe); 453 } else { 454 trigger(Event:StallAccess, in_msg.addr, cache_entry, tbe); 455 } 456 } else if (isOutstanding(tbe, cache_entry, in_msg.addr)) { 457 DPRINTF(RubySlicc, "Stall outstanding request %s\n", in_msg.Type); 458 trigger(Event:StallAccess, in_msg.addr, cache_entry, tbe); 459 } else { 460 if (presentOrAvail(in_msg.addr)) { 461 if (in_msg.Type == CoherenceRequestType:RdBlkM ) { 462 trigger(Event:CPUWrite, in_msg.addr, cache_entry, tbe); 463 } else if (in_msg.Type == CoherenceRequestType:WriteThrough ) { 464 trigger(Event:CPUWrite, in_msg.addr, cache_entry, tbe); 465 } else if (in_msg.Type == CoherenceRequestType:Atomic ) { 466 trigger(Event:CPUWrite, in_msg.addr, cache_entry, tbe); 467 } else { 468 if (in_msg.Type == CoherenceRequestType:VicDirty || 469 in_msg.Type == CoherenceRequestType:VicClean) { 470 trigger(Event:CPUWriteback, in_msg.addr, cache_entry, tbe); 471 } else { 472 trigger(Event:CPURead, in_msg.addr, cache_entry, tbe); 473 } 474 } 475 } else { 476 Addr victim := cacheMemory.cacheProbe(getRegionBase(in_msg.addr)); 477 TBE victim_tbe := getTBE(victim); 478 Entry victim_entry := getCacheEntry(victim); 479 DPRINTF(RubySlicc, "Replacing region %s for %s(%s)\n", victim, in_msg.addr, getRegionBase(in_msg.addr)); 480 trigger(Event:ReplRegion, victim, victim_entry, victim_tbe); 481 } 482 } 483 } 484 } 485 } 486 487 // Actions 488 action(f_fwdReqToDir, "f", desc="Forward CPU request to directory") { 489 peek(requestNetwork_in, CPURequestMsg) { 490 enqueue(requestNetwork_out, CPURequestMsg, toDirLatency) { 491 out_msg.addr := in_msg.addr; 492 out_msg.Type := in_msg.Type; 493 out_msg.DataBlk := in_msg.DataBlk; 494 out_msg.Dirty := in_msg.Dirty; 495 out_msg.Requestor := in_msg.Requestor; 496 out_msg.WTRequestor := in_msg.WTRequestor; 497 out_msg.Destination.add(mapAddressToMachine(in_msg.addr, MachineType:Directory)); 498 out_msg.Shared := in_msg.Shared; 499 out_msg.MessageSize := in_msg.MessageSize; 500 out_msg.Private := true; 501 out_msg.InitialRequestTime := curCycle(); 502 out_msg.ProbeRequestStartTime := curCycle(); 503 if (getState(tbe, cache_entry, address) == State:S) { 504 out_msg.ForceShared := true; 505 } 506 DPRINTF(RubySlicc, "Fwd: %s\n", out_msg); 507 //assert(getState(tbe, cache_entry, address) == State:P || getState(tbe, cache_entry, address) == State:S); 508 if (getState(tbe, cache_entry, address) == State:NP_W) { 509 APPEND_TRANSITION_COMMENT(" fwding stale request: "); 510 APPEND_TRANSITION_COMMENT(out_msg.Type); 511 } 512 } 513 } 514 } 515 516 action(u_updateRegionEntry, "u", desc="Update the entry for profiling") { 517 peek(requestNetwork_in, CPURequestMsg) { 518 if (is_valid(cache_entry)) { 519 if (in_msg.CtoDSinked == false) { 520 APPEND_TRANSITION_COMMENT(" incr outstanding "); 521 cache_entry.NumOutstandingReqs := 1 + cache_entry.NumOutstandingReqs; 522 assert(cache_entry.OutstandingReqs.at(getRegionOffset(address)) == false); 523 cache_entry.OutstandingReqs.at(getRegionOffset(address)) := true; 524 assert(cache_entry.NumOutstandingReqs == countBoolVec(cache_entry.OutstandingReqs)); 525 } else { 526 APPEND_TRANSITION_COMMENT(" NOT incr outstanding "); 527 assert(in_msg.Type == CoherenceRequestType:RdBlkM || in_msg.Type == CoherenceRequestType:RdBlkS); 528 } 529 APPEND_TRANSITION_COMMENT(cache_entry.NumOutstandingReqs); 530 if (in_msg.Type == CoherenceRequestType:RdBlkM || in_msg.Type == CoherenceRequestType:Atomic || 531 in_msg.Type == CoherenceRequestType:WriteThrough ) 532 { 533 cache_entry.dirty := true; 534 } 535 if (in_msg.Type == CoherenceRequestType:VicDirty || 536 in_msg.Type == CoherenceRequestType:VicClean) { 537 DPRINTF(RubySlicc, "Got %s for addr %s\n", in_msg.Type, address); 538 //assert(cache_entry.ValidBlocks.at(getRegionOffset(address))); 539 // can in fact be inv if core got an inv after a vicclean before it got here 540 if (cache_entry.ValidBlocks.at(getRegionOffset(address))) { 541 cache_entry.clearOnDone := true; 542 cache_entry.clearOnDoneAddr := address; 543 //cache_entry.ValidBlocks.at(getRegionOffset(address)) := false; 544 //cache_entry.NumValidBlocks := cache_entry.NumValidBlocks - 1; 545 } 546 } else { 547 if (cache_entry.ValidBlocks.at(getRegionOffset(address)) == false) { 548 cache_entry.NumValidBlocks := cache_entry.NumValidBlocks + 1; 549 } 550 DPRINTF(RubySlicc, "before valid addr %s bits %s\n", 551 in_msg.Type, address, cache_entry.ValidBlocks); 552 cache_entry.ValidBlocks.at(getRegionOffset(address)) := true; 553 DPRINTF(RubySlicc, "after valid addr %s bits %s\n", 554 in_msg.Type, address, cache_entry.ValidBlocks); 555 cache_entry.UsedBlocks.at(getRegionOffset(address)) := true; 556 } 557 assert(cache_entry.NumValidBlocks <= blocksPerRegion); 558 assert(cache_entry.NumValidBlocks >= 0); 559 APPEND_TRANSITION_COMMENT(" valid blocks "); 560 APPEND_TRANSITION_COMMENT(cache_entry.ValidBlocks); 561 } else { 562 error("This shouldn't happen anymore I think"); 563 //tbe.ValidBlocks.at(getRegionOffest(address)) := true; 564 assert(getState(tbe, cache_entry, address) == State:P_NP); 565 } 566 } 567 } 568 569 action(uw_updatePossibleWriteback, "uw", desc="writeback request complete") { 570 peek(unblockNetwork_in, UnblockMsg) { 571 if (is_valid(cache_entry) && in_msg.validToInvalid && 572 cache_entry.clearOnDone && cache_entry.clearOnDoneAddr == address) { 573 DPRINTF(RubySlicc, "I have no idea what is going on here\n"); 574 cache_entry.ValidBlocks.at(getRegionOffset(address)) := false; 575 cache_entry.NumValidBlocks := cache_entry.NumValidBlocks - 1; 576 cache_entry.clearOnDone := false; 577 } 578 } 579 } 580 581 582 action(rp_requestPrivate, "rp", desc="Send private request r-dir") { 583 peek(requestNetwork_in, CPURequestMsg) { 584 // No need to send acks on replacements 585 assert(is_invalid(tbe)); 586 enqueue(requestNetwork_out, CPURequestMsg, toRegionDirLatency) { 587 out_msg.addr := address; // use the actual address so the demand request can be fulfilled 588 out_msg.DemandAddress := address; 589 out_msg.Type := CoherenceRequestType:PrivateRequest; 590 out_msg.OriginalType := in_msg.Type; 591 out_msg.Requestor := machineID; 592 out_msg.WTRequestor := in_msg.WTRequestor; 593 out_msg.InitialRequestTime := curCycle(); 594 // will this always be ok? probably not for multisocket 595 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 596 out_msg.MessageSize := MessageSizeType:Request_Control; 597 DPRINTF(RubySlicc, "Private request %s\n", out_msg); 598 } 599 cache_entry.ProbeRequestTime := curCycle(); 600 cache_entry.MsgSentToDir := true; 601 APPEND_TRANSITION_COMMENT(getRegionBase(address)); 602 } 603 } 604 605 action(ru_requestUpgrade, "ru", desc="Send upgrade request r-dir") { 606 peek(requestNetwork_in, CPURequestMsg) { 607 // No need to send acks on replacements 608 assert(is_invalid(tbe)); 609 enqueue(requestNetwork_out, CPURequestMsg, toRegionDirLatency) { 610 out_msg.addr := address; // use the actual address so the demand request can be fulfilled 611 out_msg.Type := CoherenceRequestType:UpgradeRequest; 612 out_msg.OriginalType := in_msg.Type; 613 out_msg.Requestor := machineID; 614 out_msg.WTRequestor := in_msg.WTRequestor; 615 out_msg.InitialRequestTime := curCycle(); 616 // will this always be ok? probably not for multisocket 617 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 618 out_msg.MessageSize := MessageSizeType:Request_Control; 619 } 620 cache_entry.ProbeRequestTime := curCycle(); 621 cache_entry.MsgSentToDir := true; 622 APPEND_TRANSITION_COMMENT(getRegionBase(address)); 623 } 624 } 625 626 action(rw_requestWriteback, "rq", desc="Send writeback request") { 627 // No need to send acks on replacements 628 enqueue(requestNetwork_out, CPURequestMsg, toRegionDirLatency) { 629 out_msg.addr := getRegionBase(address); // use the actual address so the demand request can be fulfilled 630 out_msg.Type := CoherenceRequestType:CleanWbRequest; 631 out_msg.Requestor := machineID; 632 // will this always be ok? probably not for multisocket 633 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 634 out_msg.MessageSize := MessageSizeType:Request_Control; 635 out_msg.Dirty := tbe.dirty; 636 APPEND_TRANSITION_COMMENT(getRegionBase(address)); 637 } 638 } 639 640 action(rs_requestShared, "rs", desc="Send shared request r-dir") { 641 peek(requestNetwork_in, CPURequestMsg) { 642 // No need to send acks on replacements 643 assert(is_invalid(tbe)); 644 enqueue(requestNetwork_out, CPURequestMsg, toRegionDirLatency) { 645 out_msg.addr := address; // use the actual address so the demand request can be fulfilled 646 out_msg.Type := CoherenceRequestType:SharedRequest; 647 out_msg.OriginalType := in_msg.Type; 648 out_msg.Requestor := machineID; 649 out_msg.WTRequestor := in_msg.WTRequestor; 650 out_msg.InitialRequestTime := curCycle(); 651 // will this always be ok? probably not for multisocket 652 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 653 out_msg.MessageSize := MessageSizeType:Request_Control; 654 } 655 cache_entry.ProbeRequestTime := curCycle(); 656 cache_entry.MsgSentToDir := true; 657 APPEND_TRANSITION_COMMENT(getRegionBase(address)); 658 } 659 } 660 661 action(ai_ackRegionInv, "ai", desc="Send ack to r-dir on region inv if tbe says so") { 662 // No need to send acks on replacements 663 assert(is_valid(tbe)); 664 enqueue(responseNetwork_out, ResponseMsg, toRegionDirLatency) { 665 out_msg.addr := getRegionBase(address); 666 out_msg.Type := CoherenceResponseType:CPUPrbResp; 667 out_msg.Sender := machineID; 668 // will this always be ok? probably not for multisocket 669 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 670 out_msg.MessageSize := MessageSizeType:Response_Control; 671 } 672 } 673 674 action(ad_ackDircetory, "ad", desc="send probe response to directory") { 675 if (noTCCdir && tbe.MsgType == ProbeRequestType:PrbDowngrade && isOnGPU()) { //VIPER tcc doesnt understand PrbShrData 676 assert(tbe.DemandRequest); //So, let RegionBuffer take care of sending back ack 677 enqueue(responseNetwork_out, ResponseMsg, toDirLatency) { 678 out_msg.addr := tbe.DemandAddress; 679 out_msg.Type := CoherenceResponseType:CPUPrbResp; // L3 and CPUs respond in same way to probes 680 out_msg.Sender := getPeer(machineID,address); 681 // will this always be ok? probably not for multisocket 682 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 683 out_msg.Dirty := false; // only true if sending back data i think 684 out_msg.Hit := false; 685 out_msg.Ntsl := false; 686 out_msg.State := CoherenceState:NA; 687 out_msg.NoAckNeeded := true; 688 out_msg.MessageSize := MessageSizeType:Response_Control; 689 DPRINTF(RubySlicc, "%s\n", out_msg); 690 } 691 } 692 } 693 694 action(aie_ackRegionExclusiveInv, "aie", desc="Send ack to r-dir on region inv if tbe says so") { 695 // No need to send acks on replacements 696 assert(is_valid(tbe)); 697 enqueue(responseNetwork_out, ResponseMsg, toRegionDirLatency) { 698 out_msg.addr := getRegionBase(address); 699 out_msg.Type := CoherenceResponseType:CPUPrbResp; 700 out_msg.Sender := machineID; 701 out_msg.NotCached := true; 702 // will this always be ok? probably not for multisocket 703 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 704 out_msg.MessageSize := MessageSizeType:Response_Control; 705 out_msg.Dirty := tbe.dirty; 706 } 707 } 708 709 action(ain_ackRegionInvNow, "ain", desc="Send ack to r-dir on region inv") { 710 enqueue(responseNetwork_out, ResponseMsg, toRegionDirLatency) { 711 out_msg.addr := getRegionBase(address); 712 out_msg.Type := CoherenceResponseType:CPUPrbResp; 713 out_msg.Sender := machineID; 714 // will this always be ok? probably not for multisocket 715 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 716 out_msg.MessageSize := MessageSizeType:Response_Control; 717 } 718 } 719 720 action(aine_ackRegionInvExlusiveNow, "aine", desc="Send ack to r-dir on region inv with exlusive permission") { 721 enqueue(responseNetwork_out, ResponseMsg, toRegionDirLatency) { 722 out_msg.addr := getRegionBase(address); 723 out_msg.Type := CoherenceResponseType:CPUPrbResp; 724 out_msg.Sender := machineID; 725 out_msg.NotCached := true; 726 // will this always be ok? probably not for multisocket 727 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 728 out_msg.MessageSize := MessageSizeType:Response_Control; 729 } 730 } 731 732 action(ap_ackPrivateNotify, "ap", desc="Send ack to r-dir on private notify") { 733 enqueue(responseNetwork_out, ResponseMsg, toRegionDirLatency) { 734 out_msg.addr := getRegionBase(address); 735 out_msg.Type := CoherenceResponseType:PrivateAck; 736 out_msg.Sender := machineID; 737 // will this always be ok? probably not for multisocket 738 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 739 out_msg.MessageSize := MessageSizeType:Response_Control; 740 } 741 } 742 743 action(aw_ackWbNotify, "aw", desc="Send ack to r-dir on writeback notify") { 744 peek(notifyNetwork_in, CPURequestMsg) { 745 if (in_msg.NoAckNeeded == false) { 746 enqueue(responseNetwork_out, ResponseMsg, toRegionDirLatency) { 747 out_msg.addr := getRegionBase(address); 748 out_msg.Type := CoherenceResponseType:RegionWbAck; 749 out_msg.Sender := machineID; 750 // will this always be ok? probably not for multisocket 751 out_msg.Destination.add(mapAddressToMachine(address, MachineType:RegionDir)); 752 out_msg.MessageSize := MessageSizeType:Response_Control; 753 } 754 } 755 } 756 } 757 758 action(e_evictCurrent, "e", desc="Evict this block in the region") { 759 // send force invalidate message to directory to invalidate this block 760 // must invalidate all blocks since region buffer could have privitized it 761 if (tbe.ValidBlocks.at(getRegionOffset(address)) && 762 (tbe.DemandRequest == false || tbe.DemandAddress != address)) { 763 DPRINTF(RubySlicc, "trying to evict address %s (base: %s, offset: %d)\n", address, getRegionBase(address), getRegionOffset(address)); 764 DPRINTF(RubySlicc, "tbe valid blocks %s\n", tbe.ValidBlocks); 765 766 enqueue(probeNetwork_out, NBProbeRequestMsg, 1) { 767 out_msg.addr := address; 768 out_msg.Type := tbe.MsgType; 769 out_msg.ReturnData := true; 770 if (address == tbe.DemandAddress) { 771 out_msg.DemandRequest := true; 772 } 773 out_msg.MessageSize := MessageSizeType:Control; 774 out_msg.Destination.add(getPeer(machineID,address)); 775 DPRINTF(RubySlicc, "%s\n", out_msg); 776 } 777 APPEND_TRANSITION_COMMENT(" current "); 778 APPEND_TRANSITION_COMMENT(tbe.ValidBlocks.at(getRegionOffset(address))); 779 tbe.AllAcksReceived := false; 780 } else { 781 DPRINTF(RubySlicc, "Not evicting demand %s\n", address); 782 } 783 } 784 785 action(ed_evictDemand, "ed", desc="Evict the demand request if it's valid") { 786 if (noTCCdir && tbe.MsgType == ProbeRequestType:PrbDowngrade && isOnGPU()) { 787 tbe.OutstandingAcks := 0; 788 tbe.AllAcksReceived := true; 789 tbe.DoneEvicting := true; 790 enqueue(triggerQueue_out, TriggerMsg, 1) { 791 out_msg.Type := TriggerType:AcksComplete; 792 out_msg.addr := getRegionBase(address); 793 } 794 } else if (tbe.DemandRequest) { 795 enqueue(probeNetwork_out, NBProbeRequestMsg, 1) { 796 out_msg.addr := tbe.DemandAddress; 797 out_msg.Type := tbe.MsgType; 798 out_msg.ReturnData := true; 799 out_msg.DemandRequest := true; 800 out_msg.MessageSize := MessageSizeType:Control; 801 out_msg.Destination.add(getPeer(machineID,address)); 802 DPRINTF(RubySlicc, "%s\n", out_msg); 803 tbe.AllAcksReceived := false; 804 } 805 if (tbe.ValidBlocks.at(getRegionOffset(tbe.DemandAddress)) == false) { 806 tbe.OutstandingAcks := tbe.OutstandingAcks + 1; 807 } 808 APPEND_TRANSITION_COMMENT("Evicting demand "); 809 APPEND_TRANSITION_COMMENT(tbe.DemandAddress); 810 } 811 APPEND_TRANSITION_COMMENT("waiting acks "); 812 APPEND_TRANSITION_COMMENT(tbe.OutstandingAcks); 813 } 814 815 action(adp_AckDemandProbe, "fp", desc="forward demand probe even if we know that the core is invalid") { 816 peek(probeNetwork_in, NBProbeRequestMsg) { 817 if (in_msg.DemandRequest) { 818 enqueue(responseNetwork_out, ResponseMsg, toDirLatency) { 819 out_msg.addr := in_msg.DemandAddress; 820 out_msg.Type := CoherenceResponseType:CPUPrbResp; // L3 and CPUs respond in same way to probes 821 out_msg.Sender := getPeer(machineID,address); 822 // will this always be ok? probably not for multisocket 823 out_msg.Destination.add(mapAddressToMachine(address, MachineType:Directory)); 824 out_msg.Dirty := false; // only true if sending back data i think 825 out_msg.Hit := false; 826 out_msg.Ntsl := false; 827 out_msg.State := CoherenceState:NA; 828 out_msg.NoAckNeeded := true; 829 out_msg.MessageSize := MessageSizeType:Response_Control; 830 DPRINTF(RubySlicc, "%s\n", out_msg); 831 } 832 } 833 } 834 } 835 836 action(en_enqueueNextEvict, "en", desc="Queue evict the next block in the region") { 837 // increment in_msg.addr by blockSize bytes and enqueue on triggerPort 838 // Only enqueue if the next address doesn't overrun the region bound 839 if (getRegionBase(getNextBlock(address)) == getRegionBase(address)) { 840 enqueue(triggerQueue_out, TriggerMsg, nextEvictLatency) { 841 out_msg.Type := TriggerType:InvNext; 842 out_msg.addr := getNextBlock(address); 843 } 844 } else { 845 tbe.DoneEvicting := true; 846 DPRINTF(RubySlicc, "Done evicing region %s\n", getRegionBase(address)); 847 DPRINTF(RubySlicc, "Waiting for %s acks\n", tbe.OutstandingAcks); 848 if (tbe.AllAcksReceived == true) { 849 enqueue(triggerQueue_out, TriggerMsg, 1) { 850 out_msg.Type := TriggerType:AcksComplete; 851 out_msg.addr := getRegionBase(address); 852 } 853 } 854 } 855 } 856 857 action(ef_enqueueFirstEvict, "ef", desc="Queue the first block in the region to be evicted") { 858 if (tbe.DoneEvicting == false) { 859 enqueue(triggerQueue_out, TriggerMsg, nextEvictLatency) { 860 out_msg.Type := TriggerType:InvNext; 861 out_msg.addr := getRegionBase(address); 862 } 863 } 864 } 865 866 action(ra_receiveAck, "ra", desc="Mark TBE entry as received this ack") { 867 DPRINTF(RubySlicc, "received ack for %s reg: %s vec: %s pos: %d\n", 868 address, getRegionBase(address), tbe.ValidBlocks, getRegionOffset(address)); 869 peek(unblockNetwork_in, UnblockMsg) { 870 // 871 // Note the tbe ValidBlock vec will be a conservative list of the 872 // valid blocks since the cache entry ValidBlock vec is set on the 873 // request 874 // 875 if (in_msg.wasValid) { 876 assert(tbe.ValidBlocks.at(getRegionOffset(address))); 877 } 878 } 879 tbe.OutstandingAcks := tbe.OutstandingAcks - 1; 880 tbe.AcksReceived.at(getRegionOffset(address)) := true; 881 assert(tbe.OutstandingAcks >= 0); 882 if (tbe.OutstandingAcks == 0) { 883 tbe.AllAcksReceived := true; 884 if (tbe.DoneEvicting) { 885 enqueue(triggerQueue_out, TriggerMsg, 1) { 886 out_msg.Type := TriggerType:AcksComplete; 887 out_msg.addr := getRegionBase(address); 888 } 889 } 890 } 891 892 APPEND_TRANSITION_COMMENT(getRegionBase(address)); 893 APPEND_TRANSITION_COMMENT(" Acks left receive "); 894 APPEND_TRANSITION_COMMENT(tbe.OutstandingAcks); 895 } 896 897 action(do_decrementOutstanding, "do", desc="Decrement outstanding requests") { 898 APPEND_TRANSITION_COMMENT(" decr outstanding "); 899 if (is_valid(cache_entry)) { 900 cache_entry.NumOutstandingReqs := cache_entry.NumOutstandingReqs - 1; 901 assert(cache_entry.OutstandingReqs.at(getRegionOffset(address))); 902 cache_entry.OutstandingReqs.at(getRegionOffset(address)) := false; 903 assert(cache_entry.NumOutstandingReqs >= 0); 904 assert(cache_entry.NumOutstandingReqs == countBoolVec(cache_entry.OutstandingReqs)); 905 APPEND_TRANSITION_COMMENT(cache_entry.NumOutstandingReqs); 906 } 907 if (is_valid(tbe)) { 908 tbe.NumOutstandingReqs := tbe.NumOutstandingReqs - 1; 909 assert(tbe.OutstandingReqs.at(getRegionOffset(address))); 910 tbe.OutstandingReqs.at(getRegionOffset(address)) := false; 911 assert(tbe.NumOutstandingReqs >= 0); 912 assert(tbe.NumOutstandingReqs == countBoolVec(tbe.OutstandingReqs)); 913 APPEND_TRANSITION_COMMENT(tbe.NumOutstandingReqs); 914 } 915 } 916 917 action(co_checkOutstanding, "co", desc="check if there are no more outstanding requests") { 918 assert(is_valid(tbe)); 919 if ((tbe.NumOutstandingReqs <= tbe.OutstandingThreshold) && 920 (tbe.AllOutstandingTriggered == false)) { 921 APPEND_TRANSITION_COMMENT(" no more outstanding: "); 922 APPEND_TRANSITION_COMMENT(tbe.NumOutstandingReqs); 923 APPEND_TRANSITION_COMMENT(tbe.OutstandingThreshold); 924 enqueue(triggerQueue_out, TriggerMsg, 1) { 925 out_msg.Type := TriggerType:AllOutstanding; 926 if (tbe.DemandRequest) { 927 out_msg.addr := tbe.DemandAddress; 928 } else { 929 out_msg.addr := getRegionBase(address); 930 } 931 DPRINTF(RubySlicc, "co enqueuing %s\n", out_msg); 932 tbe.AllOutstandingTriggered := true; 933 } 934 } else { 935 APPEND_TRANSITION_COMMENT(" still more outstanding "); 936 } 937 } 938 939 action(ro_resetAllOutstanding, "ro", desc="Reset all outstanding") { 940 tbe.AllOutstandingTriggered := false; 941 } 942 943 action(so_setOutstandingCheckOne, "so", desc="Check outstanding is waiting for 1, not 0") { 944 // Need this for S_P because one request is outstanding between here and r-dir 945 tbe.OutstandingThreshold := 1; 946 } 947 948 action(a_allocateRegionEntry, "a", desc="Allocate a new entry") { 949 set_cache_entry(cacheMemory.allocate(getRegionBase(address), new Entry)); 950 cache_entry.ValidBlocks.clear(); 951 cache_entry.ValidBlocks.resize(blocksPerRegion); 952 cache_entry.UsedBlocks.clear(); 953 cache_entry.UsedBlocks.resize(blocksPerRegion); 954 cache_entry.dirty := false; 955 cache_entry.NumOutstandingReqs := 0; 956 cache_entry.OutstandingReqs.clear(); 957 cache_entry.OutstandingReqs.resize(blocksPerRegion); 958 } 959 960 action(d_deallocateRegionEntry, "d", desc="Deallocate region entry") { 961 cacheMemory.deallocate(getRegionBase(address)); 962 unset_cache_entry(); 963 } 964 965 action(t_allocateTBE, "t", desc="allocate TBE Entry") { 966 check_allocate(TBEs); 967 TBEs.allocate(getRegionBase(address)); 968 set_tbe(getTBE(address)); 969 tbe.OutstandingAcks := 0; 970 tbe.AllAcksReceived := true; // starts true since the region could be empty 971 tbe.DoneEvicting := false; 972 tbe.AcksReceived.clear(); 973 tbe.AcksReceived.resize(blocksPerRegion); 974 tbe.SendAck := false; 975 tbe.OutstandingThreshold := 0; 976 if (is_valid(cache_entry)) { 977 tbe.NumOutstandingReqs := cache_entry.NumOutstandingReqs; 978 tbe.OutstandingReqs := cache_entry.OutstandingReqs; 979 assert(tbe.NumOutstandingReqs == countBoolVec(tbe.OutstandingReqs)); 980 tbe.dirty := cache_entry.dirty; 981 tbe.ValidBlocks := cache_entry.ValidBlocks; 982 tbe.OutstandingAcks := countBoolVec(tbe.ValidBlocks); 983 APPEND_TRANSITION_COMMENT(" tbe valid blocks "); 984 APPEND_TRANSITION_COMMENT(tbe.ValidBlocks); 985 APPEND_TRANSITION_COMMENT(" cache valid blocks "); 986 APPEND_TRANSITION_COMMENT(cache_entry.ValidBlocks); 987 } else { 988 tbe.dirty := false; 989 } 990 } 991 992 action(m_markSendAck, "m", desc="Mark TBE that we need to ack at end") { 993 assert(is_valid(tbe)); 994 tbe.SendAck := true; 995 } 996 997 action(db_markDirtyBit, "db", desc="Mark TBE dirty bit") { 998 peek(unblockNetwork_in, UnblockMsg) { 999 if (is_valid(tbe)) { 1000 tbe.dirty := tbe.dirty || in_msg.Dirty; 1001 } 1002 } 1003 } 1004 1005 action(dr_markDoneAckReceived, "dr", desc="Mark TBE that a done ack has been received") { 1006 assert(is_valid(tbe)); 1007 tbe.DoneAckReceived := true; 1008 tbe.DoneAckAddr := address; 1009 APPEND_TRANSITION_COMMENT(" marking done ack on TBE "); 1010 } 1011 1012 action(se_setTBE, "se", desc="Set msg type to evict") { 1013 peek(probeNetwork_in, NBProbeRequestMsg) { 1014 tbe.MsgType := in_msg.Type; 1015 tbe.Requestor := in_msg.Requestor; 1016 tbe.DemandAddress := in_msg.DemandAddress; 1017 tbe.DemandRequest := in_msg.DemandRequest; 1018 } 1019 } 1020 1021 action(sne_setNewTBE, "sne", desc="Set msg type to evict") { 1022 peek(probeNetwork_in, NBProbeRequestMsg) { 1023 tbe.NewMsgType := in_msg.Type; 1024 tbe.NewRequestor := in_msg.Requestor; 1025 tbe.NewDemandAddress := in_msg.DemandAddress; 1026 tbe.NewDemandRequest := in_msg.DemandRequest; 1027 } 1028 } 1029 1030 action(soe_setOldTBE, "soe", desc="Set msg type to evict") { 1031 tbe.MsgType := tbe.NewMsgType; 1032 tbe.Requestor := tbe.NewRequestor; 1033 tbe.DemandAddress := tbe.NewDemandAddress; 1034 tbe.DemandRequest := tbe.NewDemandRequest; 1035 tbe.OutstandingAcks := countBoolVec(tbe.ValidBlocks); 1036 tbe.AllAcksReceived := true; // starts true since the region could be empty 1037 tbe.DoneEvicting := false; 1038 tbe.AcksReceived.clear(); 1039 tbe.AcksReceived.resize(blocksPerRegion); 1040 tbe.SendAck := false; 1041 } 1042 1043 action(ser_setTBE, "ser", desc="Set msg type to evict repl") { 1044 tbe.MsgType := ProbeRequestType:PrbInv; 1045 } 1046 1047 action(md_setMustDowngrade, "md", desc="When permissions finally get here, must be shared") { 1048 assert(is_valid(cache_entry)); 1049 cache_entry.MustDowngrade := true; 1050 } 1051 1052 action(dt_deallocateTBE, "dt", desc="deallocate TBE Entry") { 1053 TBEs.deallocate(getRegionBase(address)); 1054 unset_tbe(); 1055 } 1056 1057 action(p_popRequestQueue, "p", desc="Pop the request queue") { 1058 requestNetwork_in.dequeue(clockEdge()); 1059 } 1060 1061 action(pl_popUnblockQueue, "pl", desc="Pop the unblock queue") { 1062 unblockNetwork_in.dequeue(clockEdge()); 1063 } 1064 1065 action(pn_popNotifyQueue, "pn", desc="Pop the notify queue") { 1066 notifyNetwork_in.dequeue(clockEdge()); 1067 } 1068 1069 action(pp_popProbeQueue, "pp", desc="Pop the probe queue") { 1070 probeNetwork_in.dequeue(clockEdge()); 1071 } 1072 1073 action(pt_popTriggerQueue, "pt", desc="Pop the trigger queue") { 1074 DPRINTF(RubySlicc, "Trigger Before Contents: %s\n", triggerQueue_in); 1075 triggerQueue_in.dequeue(clockEdge()); 1076 DPRINTF(RubySlicc, "Trigger After Contents: %s\n", triggerQueue_in); 1077 } 1078 1079 // Must always use wake all, since non-region address wait on region addresses 1080 action(wa_wakeUpAllDependents, "wa", desc="Wake up any requests waiting for this region") { 1081 wakeUpAllBuffers(); 1082 } 1083 1084 action(zz_stallAndWaitRequestQueue, "\z", desc="recycle request queue") { 1085 Addr regAddr := getRegionBase(address); 1086 DPRINTF(RubySlicc, "Stalling address %s\n", regAddr); 1087 stall_and_wait(requestNetwork_in, regAddr); 1088 } 1089 1090 action(yy_stallAndWaitProbeQueue, "\y", desc="stall probe queue") { 1091 Addr regAddr := getRegionBase(address); 1092 stall_and_wait(probeNetwork_in, regAddr); 1093 } 1094 1095 action(yyy_recycleProbeQueue, "\yy", desc="recycle probe queue") { 1096 probeNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); 1097 } 1098 1099 action(zzz_recycleRequestQueue, "\zz", desc="recycle request queue") { 1100 requestNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); 1101 } 1102 1103 action(www_recycleUnblockNetwork, "\ww", desc="recycle unblock queue") { 1104 unblockNetwork_in.recycle(clockEdge(), cyclesToTicks(recycle_latency)); 1105 } 1106 1107 action(z_stall, "z", desc="stall request queue") { 1108 // fake state 1109 } 1110 1111 action(mru_setMRU, "mru", desc="set MRU") { 1112 cacheMemory.setMRU(address, cache_entry.NumValidBlocks); 1113 } 1114 1115 // Transitions 1116 1117 transition({NP_PS, S_P, S_NP_PS, P_NP, P_S, P_NP_O, S_NP_PS_O, P_S_O, S_O, P_NP_W, P_NP_NP, NP_W}, {CPURead, CPUWriteback, CPUWrite}) {} { 1118 zz_stallAndWaitRequestQueue; 1119 } 1120 1121 transition(SS_P, {CPURead, CPUWriteback}) { 1122 zz_stallAndWaitRequestQueue; 1123 } 1124 1125 transition({NP, S, P, NP_PS, S_P, S_NP_PS, P_NP, P_S, P_NP_O, S_NP_PS_O, P_S_O, S_O, SS_P, NP_W, P_NP_NP}, StallAccess) {} { 1126 zz_stallAndWaitRequestQueue; 1127 } 1128 1129 transition({S, P, NP_PS, S_P, S_NP_PS, P_NP, P_S, P_NP_O, S_NP_PS_O, P_S_O, S_O, SS_P, P_NP_W, P_NP_NP, NP_W}, StallDoneAck) { 1130 www_recycleUnblockNetwork; 1131 } 1132 1133 transition(NP, StallDoneAck, NP_W) { 1134 t_allocateTBE; 1135 db_markDirtyBit; 1136 dr_markDoneAckReceived; 1137 pl_popUnblockQueue; 1138 } 1139 1140 transition(NP_W, StaleRequest, NP) { 1141 f_fwdReqToDir; 1142 dt_deallocateTBE; 1143 wa_wakeUpAllDependents; 1144 p_popRequestQueue; 1145 } 1146 1147 transition(P_NP_O, DowngradeRegion) {} { 1148 z_stall; // should stall and wait 1149 } 1150 1151 transition({NP_PS, S_NP_PS, S_P, P_S, P_NP_O, S_NP_PS_O, P_S_O, S_O, SS_P}, ReplRegion) {} { 1152 zz_stallAndWaitRequestQueue; // can't let things get out of order! 1153 } 1154 1155 transition({P_NP_O, S_O, SS_P}, InvRegion) {} { 1156 yyy_recycleProbeQueue; // can't be z_stall because there could be a RdBlkM in the requestQueue which has the sinked flag which is blocking the inv 1157 } 1158 1159 transition(P_NP, {InvRegion, DowngradeRegion}, P_NP_NP) {} { 1160 sne_setNewTBE; 1161 pp_popProbeQueue; 1162 } 1163 1164 transition(S_P, DowngradeRegion) {} { 1165 adp_AckDemandProbe; 1166 ain_ackRegionInvNow; 1167 pp_popProbeQueue; 1168 } 1169 1170 transition(P_NP_W, InvRegion) { 1171 adp_AckDemandProbe; 1172 ain_ackRegionInvNow; 1173 pp_popProbeQueue; 1174 } 1175 1176 transition(P_NP_W, DowngradeRegion) { 1177 adp_AckDemandProbe; 1178 aine_ackRegionInvExlusiveNow; 1179 pp_popProbeQueue; 1180 } 1181 1182 transition({P, S}, {CPURead, CPUWriteback}) {TagArrayRead, TagArrayWrite} { 1183 mru_setMRU; 1184 f_fwdReqToDir; 1185 u_updateRegionEntry; 1186 p_popRequestQueue; 1187 } 1188 1189 transition(P, CPUWrite) {TagArrayRead, TagArrayWrite} { 1190 mru_setMRU; 1191 f_fwdReqToDir; 1192 u_updateRegionEntry; 1193 p_popRequestQueue; 1194 } 1195 1196 transition(S, CPUWrite, S_O) {TagArrayRead} { 1197 mru_setMRU; 1198 t_allocateTBE; 1199 co_checkOutstanding; 1200 zz_stallAndWaitRequestQueue; 1201 } 1202 1203 transition(S_O, AllOutstanding, SS_P) { 1204 wa_wakeUpAllDependents; 1205 ro_resetAllOutstanding; 1206 pt_popTriggerQueue; 1207 } 1208 1209 transition(SS_P, CPUWrite, S_P) { 1210 mru_setMRU; 1211 dt_deallocateTBE; 1212 ru_requestUpgrade; 1213 u_updateRegionEntry; 1214 p_popRequestQueue; 1215 } 1216 1217 transition(NP, {CPURead, CPUWriteback}, NP_PS) {TagArrayRead, TagArrayWrite} { 1218 a_allocateRegionEntry; 1219 rs_requestShared; 1220 u_updateRegionEntry; 1221 p_popRequestQueue;//zz_stallAndWaitRequestQueue; 1222 } 1223 1224 transition(NP, CPUWrite, NP_PS) {TagArrayRead, TagArrayWrite} { 1225 a_allocateRegionEntry; 1226 rp_requestPrivate; 1227 u_updateRegionEntry; 1228 p_popRequestQueue;//zz_stallAndWaitRequestQueue; 1229 } 1230 1231 transition(NP_PS, PrivateNotify, P) {} { 1232 ap_ackPrivateNotify; 1233 wa_wakeUpAllDependents; 1234 pn_popNotifyQueue; 1235 } 1236 1237 transition(S_P, PrivateNotify, P) {} { 1238 ap_ackPrivateNotify; 1239 wa_wakeUpAllDependents; 1240 pn_popNotifyQueue; 1241 } 1242 1243 transition(NP_PS, SharedNotify, S) {} { 1244 ap_ackPrivateNotify; 1245 wa_wakeUpAllDependents; 1246 pn_popNotifyQueue; 1247 } 1248 1249 transition(P_NP_W, WbNotify, NP) {} { 1250 aw_ackWbNotify; 1251 wa_wakeUpAllDependents; 1252 dt_deallocateTBE; 1253 pn_popNotifyQueue; 1254 } 1255 1256 transition({P, S}, ReplRegion, P_NP_O) {TagArrayRead, TagArrayWrite} { 1257 t_allocateTBE; 1258 ser_setTBE; 1259 d_deallocateRegionEntry; 1260 co_checkOutstanding; 1261 } 1262 1263 transition({P, S}, InvRegion, P_NP_O) {TagArrayRead, TagArrayWrite} { 1264 t_allocateTBE; 1265 se_setTBE; 1266 m_markSendAck; 1267 d_deallocateRegionEntry; 1268 co_checkOutstanding; 1269 pp_popProbeQueue; 1270 } 1271 1272 transition(P_NP_O, AllOutstanding, P_NP) {} { 1273 ed_evictDemand; 1274 ef_enqueueFirstEvict; 1275 ro_resetAllOutstanding; 1276 pt_popTriggerQueue; 1277 } 1278 1279 transition(S_P, InvRegion, S_NP_PS_O) {TagArrayRead} { 1280 t_allocateTBE; 1281 se_setTBE; 1282 m_markSendAck; 1283 so_setOutstandingCheckOne; 1284 co_checkOutstanding; 1285 pp_popProbeQueue; 1286 } 1287 1288 transition(S_NP_PS_O, AllOutstanding, S_NP_PS) { 1289 ed_evictDemand; 1290 ef_enqueueFirstEvict; 1291 ro_resetAllOutstanding; 1292 pt_popTriggerQueue; 1293 } 1294 1295 transition(P, DowngradeRegion, P_S_O) {TagArrayRead, TagArrayWrite} { 1296 t_allocateTBE; 1297 se_setTBE; 1298 m_markSendAck; 1299 co_checkOutstanding; 1300 pp_popProbeQueue; 1301 } 1302 1303 transition(P_S_O, AllOutstanding, P_S) {} { 1304 ed_evictDemand; 1305 ef_enqueueFirstEvict; 1306 ro_resetAllOutstanding; 1307 pt_popTriggerQueue; 1308 } 1309 1310 transition({P, S}, DoneAck) {TagArrayWrite} { 1311 do_decrementOutstanding; 1312 wa_wakeUpAllDependents; 1313 db_markDirtyBit; 1314 uw_updatePossibleWriteback; 1315 pl_popUnblockQueue; 1316 } 1317 1318 transition({S_P, NP_PS, S_NP_PS}, DoneAck) {TagArrayWrite} { 1319 www_recycleUnblockNetwork; 1320 } 1321 1322 transition({P_NP_O, S_NP_PS_O, P_S_O, S_O}, DoneAck) {} { 1323 do_decrementOutstanding; 1324 co_checkOutstanding; 1325 db_markDirtyBit; 1326 uw_updatePossibleWriteback; 1327 pl_popUnblockQueue; 1328 } 1329 1330 transition({P_NP, P_S, S_NP_PS, P_NP_NP}, Evict) {} { 1331 e_evictCurrent; 1332 en_enqueueNextEvict; 1333 pt_popTriggerQueue; 1334 } 1335 1336 transition({P_NP, P_S, S_NP_PS, P_NP_NP}, InvAck) {} { 1337 ra_receiveAck; 1338 db_markDirtyBit; 1339 pl_popUnblockQueue; 1340 } 1341 1342 transition(P_NP, LastAck_CleanWb, P_NP_W) {} { 1343 rw_requestWriteback; 1344 pt_popTriggerQueue; 1345 } 1346 1347 transition(P_NP_NP, LastAck_CleanWb, P_NP) {} { 1348 soe_setOldTBE; 1349 m_markSendAck; 1350 ed_evictDemand; 1351 ef_enqueueFirstEvict; 1352 pt_popTriggerQueue; 1353 } 1354 1355 transition(P_NP, LastAck_PrbResp, NP) {} { 1356 aie_ackRegionExclusiveInv; 1357 dt_deallocateTBE; 1358 wa_wakeUpAllDependents; 1359 pt_popTriggerQueue; 1360 } 1361 1362 transition(S_NP_PS, LastAck_PrbResp, NP_PS) {} { 1363 aie_ackRegionExclusiveInv; 1364 dt_deallocateTBE; 1365 wa_wakeUpAllDependents; 1366 pt_popTriggerQueue; 1367 } 1368 1369 transition(P_S, LastAck_PrbResp, S) {} { 1370 ai_ackRegionInv; 1371 ad_ackDircetory; 1372 dt_deallocateTBE; 1373 wa_wakeUpAllDependents; 1374 pt_popTriggerQueue; 1375 } 1376 1377} 1378 1379