@@ -76,7 +76,7 @@ At layer 1, cachePermissions and dirPermissions are introduced allowing dirBusy
7676to be hidden. At this layer, absMem is also introduced. The main purpose of this layer is to
7777create atomic actions with suitable mover types. Specifically, we want the following:
7878- Memory operations (read and write) to be both movers.
79- - Shared snoop request at cache to be left mover.
79+ - Shared invalidate request at cache to be left mover.
8080- Response to read request at cache to be left mover.
8181- Initiation and conclusion of cache and directory operations to be right and left movers, respectively.
8282
@@ -115,6 +115,24 @@ invariant Set_Contains(drp, CachePermission(i, Hash(ma)));
115115invariant (var line := cache[i][Hash(ma)]; (line-> state == Invalid() || line-> state == Shared()) && line-> ma == ma);
116116
117117/// Cache
118+ /*
119+ There are 5 top-level operations on the cache.
120+ cache_read and cache_write read and write a cache entry, respectively;
121+ they may nondeterministically choose not to do the operation.
122+ cache_evict_req initiates eviction of a cache line.
123+ cache_read_shd_req and cache_read_exc_req initiate bringing a memory address into the cache
124+ in Shared and Exclusive mode, respectively.
125+ The last three operations make asynchronous calls to corresponding operations on the directory
126+ to achieve their goals.
127+
128+ To specify the protocol, we introduce absMem, a global variable capturing the logical view of
129+ memory at layer 1.
130+ The verification demonstrates that cache_read and cache_read do the appropriate operation
131+ on absMem.
132+ At layer 3, all operations other than cache_read and cache_write disappear by becoming "skip"
133+ since all the concrete state is hidden by layer 2.
134+ */
135+
118136yield procedure {:layer 2 } cache_read(i: CacheId, ma: MemAddr) returns (result: Option Value)
119137preserves call YieldInv#2 ();
120138refines atomic action {:layer 3 } _ {
@@ -188,6 +206,7 @@ refines atomic action {:layer 2} _ {
188206 var line: CacheLine;
189207
190208 if (*) {
209+ // this relaxation allows cache_invalidate_shd#1 to commute to the left of cache_read#1
191210 result := Some(absMem[ma]);
192211 } else if (*) {
193212 result := None();
@@ -335,7 +354,7 @@ refines atomic action {:layer 2} _ {
335354}
336355
337356/*
338- The left mover types of the actions cache_read_resp#1 and cache_snoop_req_shd #1 are critical
357+ The left mover types of the actions cache_read_resp#1 and cache_invalidate_shd #1 are critical
339358to achieve the correct atomicity for the directory operations.
340359If the two invocations are hitting different caches, the argument is straightforward.
341360Otherwise, they are hitting the same cache and their i arguments are the same.
@@ -373,29 +392,30 @@ refines left action {:layer 2} _ {
373392 call {:layer 1 } Set_Put(cachePermissions, drp);
374393}
375394
376- yield procedure {:layer 1 } cache_snoop_req_shd #1 (i: CacheId, ma: MemAddr, s: State, {:linear} {:layer 1 } dp: Set DirPermission)
395+ yield procedure {:layer 1 } cache_invalidate_shd #1 (i: CacheId, ma: MemAddr, s: State, {:linear} {:layer 1 } dp: Set DirPermission)
377396refines left action {:layer 2 } _ {
378397 var ca: CacheAddr;
379398
380399 assert Set_Contains(dp, DirPermission(i, ma));
381400 assume {:add_to_pool "DirPermission" , DirPermission(i, ma)} true ;
382401 ca := Hash(ma);
383402 assert (forall j: CacheId :: (var line := cache[j][ca]; line-> ma == ma ==> line-> state == Invalid() || line-> state == Shared()));
403+ // this assertion accompanies the relaxation in cache_read#1 to allow cache_invalidate_shd#1 to commute to the left of cache_read#1
384404 assert cache[i][ca]-> value == absMem[ma];
385- call primitive_cache_snoop_req_shd (i, ma, s);
405+ call primitive_cache_invalidate_shd (i, ma, s);
386406}
387407{
388- call cache_snoop_req_shd #0 (i, ma, s);
408+ call cache_invalidate_shd #0 (i, ma, s);
389409}
390410
391- yield procedure {:layer 1 } cache_snoop_req_exc #1 (i: CacheId, ma: MemAddr, s: State, {:linear} {:layer 1 } dp: Set DirPermission) returns (value: Value)
411+ yield procedure {:layer 1 } cache_invalidate_exc #1 (i: CacheId, ma: MemAddr, s: State, {:linear} {:layer 1 } dp: Set DirPermission) returns (value: Value)
392412refines atomic action {:layer 2 } _ {
393413 assert dp == WholeDirPermission(ma);
394414 assume {:add_to_pool "DirPermission" , DirPermission(i0, ma)} true ;
395- call value := primitive_cache_snoop_req_exc (i, ma, s);
415+ call value := primitive_cache_invalidate_exc (i, ma, s);
396416}
397417{
398- call value := cache_snoop_req_exc #0 (i, ma, s);
418+ call value := cache_invalidate_exc #0 (i, ma, s);
399419}
400420
401421// Cache primitives
@@ -512,12 +532,12 @@ refines atomic action {:layer 1} _ {
512532 cacheBusy[i][ca] := false ;
513533}
514534
515- yield procedure {:layer 0 } cache_snoop_req_shd #0 (i: CacheId, ma: MemAddr, s: State);
535+ yield procedure {:layer 0 } cache_invalidate_shd #0 (i: CacheId, ma: MemAddr, s: State);
516536refines atomic action {:layer 1 } _ {
517- call primitive_cache_snoop_req_shd (i, ma, s);
537+ call primitive_cache_invalidate_shd (i, ma, s);
518538}
519539
520- action {:layer 1 ,2 } primitive_cache_snoop_req_shd (i: CacheId, ma: MemAddr, s: State)
540+ action {:layer 1 ,2 } primitive_cache_invalidate_shd (i: CacheId, ma: MemAddr, s: State)
521541{
522542 var ca: CacheAddr;
523543 var line: CacheLine;
@@ -530,12 +550,12 @@ action {:layer 1,2} primitive_cache_snoop_req_shd(i: CacheId, ma: MemAddr, s: St
530550 cache[i][ca]-> state := s;
531551}
532552
533- yield procedure {:layer 0 } cache_snoop_req_exc #0 (i: CacheId, ma: MemAddr, s: State) returns (value: Value);
553+ yield procedure {:layer 0 } cache_invalidate_exc #0 (i: CacheId, ma: MemAddr, s: State) returns (value: Value);
534554refines atomic action {:layer 1 } _ {
535- call value := primitive_cache_snoop_req_exc (i, ma, s);
555+ call value := primitive_cache_invalidate_exc (i, ma, s);
536556}
537557
538- action {:layer 1 ,2 } primitive_cache_snoop_req_exc (i: CacheId, ma: MemAddr, s: State) returns (value: Value)
558+ action {:layer 1 ,2 } primitive_cache_invalidate_exc (i: CacheId, ma: MemAddr, s: State) returns (value: Value)
539559{
540560 var ca: CacheAddr;
541561 var line: CacheLine;
@@ -559,7 +579,7 @@ requires call YieldEvict(i, ma, value, drp);
559579 var {:linear} {:layer 1 ,2 } dp: Set DirPermission;
560580
561581 par dirState, dp := dir_req_begin(ma) | YieldInv#1 ();
562- // do not change dirState in case this is a stale evict request due to a race condition with a snoop
582+ // do not change dirState in case this is a stale evict request due to a race condition with an invalidate
563583 if (dirState == Owner(i)) {
564584 par write_mem(ma, value, dp) | YieldInv#1 ();
565585 dirState := Sharers(Set_Empty());
@@ -584,7 +604,7 @@ requires call YieldRead(i, ma, drp);
584604
585605 par dirState, dp := dir_req_begin(ma) | YieldInv#1 ();
586606 if (dirState is Owner) {
587- par value := cache_snoop_req_exc #1 (dirState-> i, ma, Shared(), dp) | YieldInv#1 ();
607+ par value := cache_invalidate_exc #1 (dirState-> i, ma, Shared(), dp) | YieldInv#1 ();
588608 par write_mem(ma, value, dp) | YieldInv#1 ();
589609 call cache_read_resp#1 (i, ma, value, Shared(), drp, dp);
590610 par dir_req_end(ma, Sharers(Set_Add(Set_Add(Set_Empty(), dirState-> i), i)), dp) | YieldInv#1 ();
@@ -610,7 +630,7 @@ requires call YieldRead(i, ma, drp);
610630
611631 par dirState, dp := dir_req_begin(ma) | YieldInv#1 ();
612632 if (dirState is Owner) {
613- par value := cache_snoop_req_exc #1 (dirState-> i, ma, Invalid(), dp) | YieldInv#1 ();
633+ par value := cache_invalidate_exc #1 (dirState-> i, ma, Invalid(), dp) | YieldInv#1 ();
614634 par write_mem(ma, value, dp) | YieldInv#1 ();
615635 } else {
616636 call {:layer 2 } cache_s := Copy(cache);
@@ -629,7 +649,7 @@ requires call YieldRead(i, ma, drp);
629649 victim := Choice(victims-> val);
630650 victims := Set_Remove(victims, victim);
631651 par dpOne, dp := get_victim(victim, ma, dp) | YieldInv#1 ();
632- par cache_snoop_req_shd #1 (victim, ma, Invalid(), dpOne) | YieldInv#1 ();
652+ par cache_invalidate_shd #1 (victim, ma, Invalid(), dpOne) | YieldInv#1 ();
633653 par dp := put_victim(dpOne, dp) | YieldInv#1 ();
634654 }
635655 par value := read_mem(ma, dp) | YieldInv#1 ();
0 commit comments