(**************************************************************************)
(* FLASH protocol without data paths                                      *)
(**************************************************************************)
(* Run cubicle with options: -brab 3 -forward-depth 13                    *)
(*                                                                        *)
(* Translated from murphi models used in                                  *)
(*                                                                        *)
(* Ching-Tsun Chou, Phanindra K. Mannava, Seungjoon Park: A Simple Method *)
(* for Parameterized Verification of Cache Coherence Protocols. FMCAD     *)
(* 2004: 382-398                                                          *)
(*                                                                        *)
(* and                                                                    *)
(*                                                                        *)
(* Murali Talupur and Mark R. Tuttle. 2008. Going with the flow:          *)
(* parameterized verification using message flows. In Proceedings of the  *)
(* 2008 International Conference on Formal Methods in Computer-Aided      *)
(* Design (FMCAD '08), Alessandro Cimatti and Robert B. Jones             *)
(* (Eds.). IEEE Press, Piscataway, NJ, USA, , Article 10 , 8 pages.       *)
(**************************************************************************)


 ***)

type cache_state = CACHE_I | CACHE_S | CACHE_E
type node_cmd = NODE_None | NODE_Get | NODE_GetX
type uni_cmd = UNI_None | UNI_Get | UNI_GetX | UNI_Put | UNI_PutX | UNI_Nak
type inv_cmd = INV_None | INV_Inv | INV_InvAck
type rp_cmd  = RP_None | RP_Replace
type wb_cmd = WB_None | WB_Wb
type shwb_cmd = SHWB_None | SHWB_ShWb | SHWB_FAck
type nakc_cmd = NAKC_None | NAKC_Nakc

type sort = Data | Proc


(*---------------------------- Home process -----------------------------*)

var Home : proc

var ProcCmd_home : node_cmd
var InvMarked_home : bool
var CacheState_home : cache_state
var CacheData_home : proc

var UniMsg_Cmd_home : uni_cmd
var UniMsg_Proc_home : proc
var UniMsg_Data_home : proc

var InvMsg_Cmd_home : inv_cmd
var RpMsg_Cmd_home : rp_cmd

(*------------------------------ Processes ------------------------------*)

array ProcCmd[proc] : node_cmd
array InvMarked[proc] : bool
array CacheState[proc] : cache_state
array CacheData[proc] : proc

(*------------------------------ Directory ------------------------------*)

var Dir_Pending : bool
var Dir_Local : bool
var Dir_Dirty : bool
var Dir_HeadVld : bool
var Dir_HeadPtr : proc
var Dir_ShrVld : bool
array Dir_ShrSet[proc] : bool
array Dir_InvSet[proc] : bool
var Dir_ShrSet_home : bool
var Dir_InvSet_home : bool


(*------------------------------- Memory --------------------------------*)

var MemData : proc

(*------------------------------- Network -------------------------------*)

array UniMsg_Cmd[proc] : uni_cmd
array UniMsg_Proc[proc] : proc
array UniMsg_Data[proc] : proc

array InvMsg_Cmd[proc] : inv_cmd
array RpMsg_Cmd[proc] : rp_cmd

var WbMsg_Cmd : wb_cmd
var WbMsg_Proc : proc
var WbMsg_Data : proc

var ShWbMsg_Cmd : shwb_cmd
var ShWbMsg_Proc : proc
var ShWbMsg_Data : proc

var NakcMsg_Cmd : nakc_cmd


(*-------------------------- Auxiliary variables ------------------------*)

var CurrData : proc
var PrevData : proc


var Collecting : bool

array Sort[proc] : sort

(*-----------------------------------------------------------------------*)



(*---------------------------- Initial states ---------------------------*)

init (p) {

     Home <> p &&

     Dir_Pending = False &&
     Dir_Local = False &&
     Dir_Dirty = False &&
     Dir_HeadVld = False &&
     Dir_ShrVld = False &&

     WbMsg_Cmd = WB_None &&
     ShWbMsg_Cmd = SHWB_None &&
     NakcMsg_Cmd = NAKC_None &&

     ProcCmd[p] = NODE_None &&
     InvMarked[p] = False &&
     CacheState[p] = CACHE_I &&

     Dir_ShrSet[p] = False &&
     Dir_InvSet[p] = False &&

     UniMsg_Cmd[p] = UNI_None &&
     InvMsg_Cmd[p] = INV_None &&
     RpMsg_Cmd[p] = RP_None &&


     ProcCmd_home = NODE_None &&
     InvMarked_home = False &&
     CacheState_home = CACHE_I &&

     Dir_ShrSet_home = False &&
     Dir_InvSet_home = False &&

     UniMsg_Cmd_home = UNI_None &&
     InvMsg_Cmd_home = INV_None &&
     RpMsg_Cmd_home = RP_None &&

     CurrData = MemData &&
     PrevData = MemData &&

     Collecting = False
}

(*-----------------------------------------------------------------------*)




(*-------------------------- Control property ---------------------------*)

unsafe (p) { CacheState_home = CACHE_E && CacheState[p] = CACHE_E }
unsafe (i j) { CacheState[i] = CACHE_E && CacheState[j] = CACHE_E }


(*--------------------------- Data properties ---------------------------*)

unsafe () { Dir_Dirty = False && MemData <> CurrData }

unsafe ()  { CacheState_home = CACHE_E && CacheData_home <> CurrData }
unsafe (p) { CacheState[p] = CACHE_E && CacheData[p] <> CurrData }

unsafe ()  { CacheState_home = CACHE_S && Collecting = True &&
             CacheData_home <> PrevData }
unsafe (p) { CacheState[p] = CACHE_S && Collecting = True &&
             CacheData[p] <> PrevData }

unsafe ()  { CacheState_home = CACHE_S && Collecting = False &&
             CacheData_home <> CurrData }
unsafe (p) { CacheState[p] = CACHE_S && Collecting = False &&
             CacheData[p] <> CurrData }

(*-----------------------------------------------------------------------*)





(*-------------------------- Muphi rule Store ---------------------------*)

transition store (src d)
requires { Sort[src] = Proc && Sort[d] = Data && CacheState[src] = CACHE_E }
{
        CacheData[src] := d;
        CurrData := d;
}

transition store_home (d)
requires { Sort[d] = Data && CacheState_home = CACHE_E }
{
        CacheData_home := d;
        CurrData := d;
}

(*----------------------- Muphi rule PI_Remote_Get ----------------------*)

transition pi_Remote_Get (src)
requires {  Sort[src] = Proc && Home <> src && 
           ProcCmd[src] = NODE_None &&
           CacheState[src] = CACHE_I }
{
        ProcCmd[src] := NODE_Get;
        UniMsg_Cmd[src] := UNI_Get;
        UniMsg_Proc[src] := Home;

}


(*--------------------- Muphi rule PI_Local_Get_Get ---------------------*)

transition pi_Local_Get_Get_Head ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home = CACHE_I &&
           Dir_Pending = False && Dir_Dirty = True }
{
        ProcCmd_home := NODE_Get;
        Dir_Pending := True;
        UniMsg_Cmd_home := UNI_Get;
        UniMsg_Proc_home := Dir_HeadPtr;
        Collecting := False;
}


(*--------------------- Muphi rule PI_Local_Get_Put ---------------------*)

transition pi_Local_Get_Put_InvM ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home = CACHE_I &&
           Dir_Pending = False && Dir_Dirty = False &&
           InvMarked_home = True }
{
        Dir_Local := True;
        ProcCmd_home := NODE_None;
        InvMarked_home := False;
        CacheState_home := CACHE_I;
}

transition pi_Local_Get_Put ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home = CACHE_I &&
           Dir_Pending = False && Dir_Dirty = False &&
           InvMarked_home = False }
{
        Dir_Local := True;
        ProcCmd_home := NODE_None;
        CacheState_home := CACHE_S;
        CacheData_home := MemData;
}



(*---------------------- Muphi rule PI_Remote_GetX ----------------------*)

transition pi_Remote_GetX (src)
requires { Sort[src] = Proc && Home <> src &&
           ProcCmd[src] = NODE_None &&
           CacheState[src] = CACHE_I }
{
  ProcCmd[src] := NODE_GetX;
  UniMsg_Cmd[src] := UNI_GetX;
  UniMsg_Proc[src] := Home;
}


(*-------------------- Muphi rule PI_Local_GetX_GetX --------------------*)

transition pi_Local_GetX_GetX ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home <> CACHE_E &&
           Dir_Pending = False && Dir_Dirty = True }
{
  ProcCmd_home := NODE_GetX;
  Dir_Pending := True;
  UniMsg_Cmd_home := UNI_GetX;
  UniMsg_Proc_home := Dir_HeadPtr;
  Collecting := False;
}


(*-------------------- Muphi rule PI_Local_GetX_PutX --------------------*)

transition pi_Local_GetX_PutX_HeadVld ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home <> CACHE_E &&
           Dir_Pending = False && Dir_Dirty = False &&
           Dir_HeadVld = True }
{
        Dir_Local := True;
        Dir_Dirty := True;

        Dir_Pending := True;
        Dir_HeadVld := False;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case 
                         | Dir_HeadPtr = p : True
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True

                         | _ : False;

        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case 
                         | Dir_HeadPtr = p : INV_Inv
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | _ : INV_None;

        Collecting := True;
        PrevData := CurrData;

        ProcCmd_home := NODE_None;
        InvMarked_home := False;
        CacheState_home := CACHE_E;
        CacheData_home := MemData;
}


transition pi_Local_GetX_PutX ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home <> CACHE_E &&
           Dir_Pending = False && Dir_Dirty = False &&
           Dir_HeadVld = False }
{
        Dir_Local := True;
        Dir_Dirty := True;

        ProcCmd_home := NODE_None;
        InvMarked_home := False;
        CacheState_home := CACHE_E;
        CacheData_home := MemData;
}


(*---------------------- Muphi rule PI_Remote_PutX ----------------------*)

transition pi_Remote_PutX (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           ProcCmd[dst] = NODE_None &&
           CacheState[dst] = CACHE_E }
{
        CacheState[dst] := CACHE_I;
        WbMsg_Cmd := WB_Wb;
        WbMsg_Proc := dst;
        WbMsg_Data := CacheData[dst];
}


(*---------------------- Muphi rule PI_Local_PutX -----------------------*)

transition pi_Local_PutX_pending ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home = CACHE_E && 
           Dir_Pending = True }
{
        CacheState_home := CACHE_I;
        Dir_Dirty := False;
        MemData := CacheData_home;
}

transition pi_Local_PutX ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home = CACHE_E && 
           Dir_Pending = False }
{
        CacheState_home := CACHE_I;
        Dir_Local := False;
        Dir_Dirty := False;
        MemData := CacheData_home;
}


(*-------------------- Muphi rule PI_Remote_Replace ---------------------*)

transition pi_Remote_Replace (src)
requires { Sort[src] = Proc && Home <> src && 
           ProcCmd[src] = NODE_None &&
           CacheState[src] = CACHE_S }
{
  CacheState[src] := CACHE_I;
  RpMsg_Cmd[src] := RP_Replace;
}


(*--------------------- Muphi rule PI_Local_Replace ---------------------*)

transition pi_Local_Replace ()
requires { ProcCmd_home = NODE_None &&
           CacheState_home = CACHE_S }
{
        Dir_Local := False;
        CacheState_home := CACHE_I;
}



(*-------------------------- Muphi rule NI_Nak --------------------------*)

transition ni_Nak (dst)
requires { Sort[dst] = Proc && UniMsg_Cmd[dst] = UNI_Nak }
{
        UniMsg_Cmd[dst] := UNI_None;
        ProcCmd[dst] := NODE_None;
        InvMarked[dst] := False;
}

transition ni_Nak_home ()
requires { UniMsg_Cmd_home = UNI_Nak }
{
        UniMsg_Cmd_home := UNI_None;
        ProcCmd_home := NODE_None;
        InvMarked_home := False;
}

(*----------------------- Muphi rule NI_Nak_Clear -----------------------*)

transition ni_Nak_Clear ()
requires { NakcMsg_Cmd = NAKC_Nakc }
{
        NakcMsg_Cmd := NAKC_None;
        Dir_Pending := False;
}


(*--------------------- Muphi rule NI_Local_Get_Nak ---------------------*)

transition ni_Local_Get_Nak1 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Pending = True }
{
  UniMsg_Cmd[src] := UNI_Nak;
  UniMsg_Proc[src] := Home;
}

transition ni_Local_Get_Nak (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Dirty = True && Dir_Local = True &&
           CacheState_home <> CACHE_E }
{
  UniMsg_Cmd[src] := UNI_Nak;
  UniMsg_Proc[src] := Home;
}

transition ni_Local_Get_Nak (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Dirty = True && Dir_Local = False && 
           Dir_HeadPtr = src }
{
  UniMsg_Cmd[src] := UNI_Nak;
  UniMsg_Proc[src] := Home;
}


(*--------------------- Muphi rule NI_Local_Get_Get ---------------------*)

transition ni_Local_Get_Get (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Pending = False &&
           Dir_Dirty = True && 
           Dir_Local = False &&
           Dir_HeadPtr <> src }
{
  Dir_Pending := True;
  UniMsg_Cmd[src] := UNI_Get;
  UniMsg_Proc[src] := Dir_HeadPtr;
  Collecting := False;
}


(*--------------------- Muphi rule NI_Local_Get_Put ---------------------*)

transition ni_Local_Get_Put1_Head (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True }
{
        Dir_ShrVld := True;
        Dir_ShrSet[src] := True;

        Dir_InvSet_home := Dir_ShrSet_home;
        Dir_InvSet[p] := case 
                         | p = src : True 
                         | _ : Dir_ShrSet[p];

        UniMsg_Cmd[src] := UNI_Put;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
}

transition ni_Local_Get_Put1 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = False }
{
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        UniMsg_Cmd[src] := UNI_Put;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
}


transition ni_Local_Get_Put2_dirty (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = Home &&
           RpMsg_Cmd[src] <> RP_Replace &&
           Dir_Pending = False &&
           Dir_Dirty = True &&
           Dir_Local = True && CacheState_home = CACHE_E }
{
        Dir_Dirty := False;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        MemData := CacheData_home;
        CacheState_home := CACHE_S;
        UniMsg_Cmd[src] := UNI_Put;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := CacheData_home;
}


(*-------------------- Muphi rule NI_Remote_Get_Nak ---------------------*)

transition ni_Remote_Get_Nak (src dst)
requires { Sort[dst] = Proc && Home <> dst &&
           UniMsg_Cmd[src] = UNI_Get &&
           UniMsg_Proc[src] = dst &&
           CacheState[dst] <> CACHE_E }
{
        UniMsg_Cmd[src] := UNI_Nak;
        UniMsg_Proc[src] := dst;
        NakcMsg_Cmd := NAKC_Nakc;
}


(*-------------------- Muphi rule NI_Remote_Get_Put ---------------------*)

transition ni_Remote_Get_Put (src dst)
requires { Sort[src] = Proc && Sort[dst] = Proc && Home <> dst && Home <> src &&
         UniMsg_Cmd[src] = UNI_Get &&
         UniMsg_Proc[src] = dst &&
         CacheState[dst] = CACHE_E }
{
        CacheState[dst] := CACHE_S;
        UniMsg_Cmd[src] := UNI_Put;
        UniMsg_Proc[src] := dst;
        UniMsg_Data[src] := CacheData[dst];
        ShWbMsg_Cmd := SHWB_ShWb;
        ShWbMsg_Proc := src;
        ShWbMsg_Data := CacheData[dst];
}

transition ni_Remote_Get_Put_home (dst)
requires { Sort[dst] = Proc && Home <> dst &&
         UniMsg_Cmd_home = UNI_Get &&
         UniMsg_Proc_home = dst &&
         CacheState[dst] = CACHE_E }
{
        CacheState[dst] := CACHE_S;
        UniMsg_Cmd_home := UNI_Put;
        UniMsg_Proc_home := dst;
        UniMsg_Data_home := CacheData[dst];
}


(*-------------------- Muphi rule NI_Local_GetX_Nak ---------------------*)

transition ni_Local_GetX_Nak1 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = True }
{
        UniMsg_Cmd[src] := UNI_Nak;
        UniMsg_Proc[src] := Home;
}

transition ni_Local_GetX_Nak (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Dirty = True && Dir_Local = True &&
           CacheState_home <> CACHE_E }
{
        UniMsg_Cmd[src] := UNI_Nak;
        UniMsg_Proc[src] := Home;
}

transition ni_Local_GetX_Nak (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Dirty = True && Dir_Local = False &&
           Dir_HeadPtr = src }
{
        UniMsg_Cmd[src] := UNI_Nak;
        UniMsg_Proc[src] := Home;
}


(*------------------- Muphi rule NI_Local_GetX_GetX ---------------------*)

transition ni_Local_GetX_GetX (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = True &&
           Dir_Local = False && 
           Dir_HeadPtr <> src }
{
        Dir_Pending := True;
        UniMsg_Cmd[src] := UNI_GetX;
        UniMsg_Proc[src] := Dir_HeadPtr;
        Collecting := False;
}



(*------------------- Muphi rule NI_Local_GetX_PutX ---------------------*)

transition ni_Local_GetX_PutX_1 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = False &&
           Dir_Local = True &&
           ProcCmd_home = NODE_Get }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
        InvMarked_home := True;
}

transition ni_Local_GetX_PutX_2 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = False &&
           Dir_Local = True && 
           ProcCmd_home <> NODE_Get }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
}

transition ni_Local_GetX_PutX_3 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = False &&
           Dir_Local = False }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
}

transition ni_Local_GetX_PutX_4 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadPtr = src  &&
           Dir_Local = True &&
           ProcCmd_home = NODE_Get &&
           Dir_ShrSet_home = False &&
           forall_other p. Dir_ShrSet[p] = False }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
        InvMarked_home := True;
}

transition ni_Local_GetX_PutX_5 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadPtr = src  &&
           Dir_Local = True &&
           ProcCmd_home <> NODE_Get &&
           Dir_ShrSet_home = False &&
           forall_other p. Dir_ShrSet[p] = False }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
}

transition ni_Local_GetX_PutX_6 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadPtr = src  &&
           Dir_Local = False &&
           Dir_ShrSet_home = False &&
           forall_other p. Dir_ShrSet[p] = False }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;

        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
}

transition ni_Local_GetX_PutX_7 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True && 
           Dir_HeadPtr <> src &&
           Dir_Local = True &&
           ProcCmd_home <> NODE_Get }
{
        Dir_Pending := True;
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
        
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case
                         | p = src : False
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True
                         | Dir_HeadVld = True && Dir_HeadPtr = p : True
                         | _ : False;
        
        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case
                         | p = src : INV_None
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | Dir_HeadVld = True && Dir_HeadPtr = p : INV_Inv
                         | _ : INV_None;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
    
        Collecting := True;
        PrevData := CurrData;
}

transition ni_Local_GetX_PutX_8 (src pp)
requires { Sort[src] = Proc && Sort[pp] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True && 
           Dir_HeadPtr = src &&
           Dir_ShrSet[pp] = True &&
           Dir_Local = True &&
           ProcCmd_home <> NODE_Get }
{
        Dir_Pending := True;
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
        
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case
                         | p = src : False
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True
                         | Dir_HeadVld = True && Dir_HeadPtr = p : True
                         | _ : False;
        
        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case
                         | p = src : INV_None
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | Dir_HeadVld = True && Dir_HeadPtr = p : INV_Inv
                         | _ : INV_None;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
    
        Collecting := True;
        PrevData := CurrData;
}


transition ni_Local_GetX_PutX_8_home (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True && 
           Dir_HeadPtr = src &&
           Dir_ShrSet_home = True &&
           Dir_Local = True &&
           ProcCmd_home <> NODE_Get }
{
        Dir_Pending := True;
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
        
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case
                         | p = src : False
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True
                         | Dir_HeadVld = True && Dir_HeadPtr = p : True
                         | _ : False;
        
        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case
                         | p = src : INV_None
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | Dir_HeadVld = True && Dir_HeadPtr = p : INV_Inv
                         | _ : INV_None;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;
        CacheState_home := CACHE_I;
    
        Collecting := True;
        PrevData := CurrData;
}


transition ni_Local_GetX_PutX_9 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True && 
           Dir_HeadPtr <> src &&
           Dir_Local = False }
{
        Dir_Pending := True;
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
        
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case
                         | p = src : False
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True
                         | Dir_HeadVld = True && Dir_HeadPtr = p : True
                         | _ : False;
        
        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case
                         | p = src : INV_None
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | Dir_HeadVld = True && Dir_HeadPtr = p : INV_Inv
                         | _ : INV_None;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;

        Collecting := True;
        PrevData := CurrData;
}


transition ni_Local_GetX_PutX_10 (src pp)
requires { Sort[src] = Proc && Sort[pp] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True && 
           Dir_HeadPtr = src &&
           Dir_ShrSet[pp] = True &&
           Dir_Local = False }
{
        Dir_Pending := True;
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
        
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case
                         | p = src : False
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True
                         | Dir_HeadVld = True && Dir_HeadPtr = p : True
                         | _ : False;
        
        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case
                         | p = src : INV_None
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | Dir_HeadVld = True && Dir_HeadPtr = p : INV_Inv
                         | _ : INV_None;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;

        Collecting := True;
        PrevData := CurrData;
}

transition ni_Local_GetX_PutX_10_home (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = False &&
           Dir_HeadVld = True && 
           Dir_HeadPtr = src &&
           Dir_ShrSet_home = True &&
           Dir_Local = False }
{
        Dir_Pending := True;
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
        
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;

        Dir_InvSet_home := False;
        Dir_InvSet[p] := case
                         | p = src : False
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : True
                         | Dir_HeadVld = True && Dir_HeadPtr = p : True
                         | _ : False;
        
        InvMsg_Cmd_home := INV_None;
        InvMsg_Cmd[p] := case
                         | p = src : INV_None
                         | Dir_ShrVld = True && Dir_ShrSet[p] = True : INV_Inv
                         | Dir_HeadVld = True && Dir_HeadPtr = p : INV_Inv
                         | _ : INV_None;

        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := MemData;

        Collecting := True;
        PrevData := CurrData;
}


transition ni_Local_GetX_PutX_11 (src)
requires { Sort[src] = Proc && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = Home &&
           Dir_Pending = False &&
           Dir_Dirty = True &&
           Dir_Local = True && CacheState_home = CACHE_E }
{
        Dir_Local := False;
        Dir_Dirty := True;
        Dir_HeadVld := True;
        Dir_HeadPtr := src;
        Dir_ShrVld := False;
    
        Dir_ShrSet_home := False;
        Dir_ShrSet[p] := case | _ : False;
        
        Dir_InvSet_home := False;
        Dir_InvSet[p] := case | _ : False;
    
        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := Home;
        UniMsg_Data[src] := CacheData_home;
        CacheState_home := CACHE_I;
}




(*-------------------- Muphi rule NI_Local_GetX_Nak ---------------------*)

transition ni_Remote_GetX_Nak (src dst)
requires { Sort[src] = Proc && Sort[dst] = Proc && Home <> dst &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = dst &&
           CacheState[dst] <> CACHE_E }
{
        UniMsg_Cmd[src] := UNI_Nak;
        UniMsg_Proc[src] := dst;
        NakcMsg_Cmd := NAKC_Nakc;
}

transition ni_Remote_GetX_Nak_home (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           UniMsg_Cmd_home = UNI_GetX &&
           UniMsg_Proc_home = dst &&
           CacheState[dst] <> CACHE_E }
{
        UniMsg_Cmd_home := UNI_Nak;
        UniMsg_Proc_home := dst;
        NakcMsg_Cmd := NAKC_Nakc;
}


(*------------------- Muphi rule NI_Remote_GetX_PutX --------------------*)

transition ni_Remote_GetX_PutX_home (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           UniMsg_Cmd_home = UNI_GetX &&
           UniMsg_Proc_home = dst &&
           CacheState[dst] = CACHE_E }
{
        CacheState[dst] := CACHE_I;
        UniMsg_Cmd_home := UNI_PutX;
        UniMsg_Proc_home := dst;
        UniMsg_Data_home := CacheData[dst];
}

transition ni_Remote_GetX_PutX (src dst)
requires { Sort[src] = Proc && Sort[dst] = Proc && Home <> dst && Home <> src &&
           UniMsg_Cmd[src] = UNI_GetX &&
           UniMsg_Proc[src] = dst &&
           CacheState[dst] = CACHE_E }
{
        CacheState[dst] := CACHE_I;
        UniMsg_Cmd[src] := UNI_PutX;
        UniMsg_Proc[src] := dst;
        UniMsg_Data[src] := CacheData[dst];
        ShWbMsg_Cmd := SHWB_FAck;
        ShWbMsg_Proc := src;
}


(*----------------------- Muphi rule NI_Local_Put -----------------------*)

transition ni_Local_Put_inv ()
requires { UniMsg_Cmd_home = UNI_Put && InvMarked_home = True }
{
        UniMsg_Cmd_home := UNI_None;
        Dir_Pending := False;
        Dir_Dirty := False;
        Dir_Local := True;
        MemData := UniMsg_Data_home;
        ProcCmd_home := NODE_None;
        InvMarked_home := False;
        CacheState_home := CACHE_I;
}

transition ni_Local_Put ()
requires { UniMsg_Cmd_home = UNI_Put && InvMarked_home = False }
{
        UniMsg_Cmd_home := UNI_None;
        Dir_Pending := False;
        Dir_Dirty := False;
        Dir_Local := True;
        MemData := UniMsg_Data_home;
        ProcCmd_home := NODE_None;
        CacheState_home := CACHE_S;
        CacheData_home := UniMsg_Data_home;
}


(*----------------------- Muphi rule NI_Remote_Put ----------------------*)

transition ni_Remote_Put_inv (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           UniMsg_Cmd[dst] = UNI_Put &&
           InvMarked[dst] = True }
{
        UniMsg_Cmd[dst] := UNI_None;
        ProcCmd[dst] := NODE_None;
        InvMarked[dst] := False;
        CacheState[dst] := CACHE_I;
}

transition ni_Remote_Put (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           UniMsg_Cmd[dst] = UNI_Put &&
           InvMarked[dst] = False }
{
        UniMsg_Cmd[dst] := UNI_None;
        ProcCmd[dst] := NODE_None;
        CacheState[dst] := CACHE_S;
        CacheData[dst] := UniMsg_Data[dst];
}


(*----------------- Muphi rule NI_Local_PutXAcksDone -------------------*)

transition ni_Local_PutXAcksDone ()
requires { UniMsg_Cmd_home = UNI_PutX }
{
        UniMsg_Cmd_home := UNI_None;
        Dir_Pending := False;
        Dir_Local := True;
        Dir_HeadVld := False;
        ProcCmd_home := NODE_None;
        InvMarked_home := False;
        CacheState_home := CACHE_E;
        CacheData_home := UniMsg_Data_home;
}


(*---------------------- Muphi rule NI_Remote_PutX ----------------------*)

transition ni_Remote_PutX (dst)
requires { Sort[dst] = Proc && Home <> dst &&
         UniMsg_Cmd[dst] = UNI_PutX &&
         ProcCmd[dst] = NODE_GetX }
{
        UniMsg_Cmd[dst] := UNI_None;
        ProcCmd[dst] := NODE_None;
        InvMarked[dst] := False;
        CacheState[dst] := CACHE_E;
        CacheData[dst] := UniMsg_Data[dst];
}


(*-------------------------- Muphi rule NI_Inv --------------------------*)

transition ni_Inv_get (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           InvMsg_Cmd[dst] = INV_Inv &&
           ProcCmd[dst] = NODE_Get }
{
        InvMsg_Cmd[dst] := INV_InvAck;
        CacheState[dst] := CACHE_I;
        InvMarked[dst] := True;
}

transition ni_Inv (dst)
requires { Sort[dst] = Proc && Home <> dst &&
           InvMsg_Cmd[dst] = INV_Inv &&
           ProcCmd[dst] <> NODE_Get }
{
        InvMsg_Cmd[dst] := INV_InvAck;
        CacheState[dst] := CACHE_I;
}


(*------------------------- Muphi rule NI_InvAck ------------------------*)

transition ni_InvAck_exists (src pp)
requires { Sort[src] = Proc && Sort[pp] = Proc && Home <> src &&
           InvMsg_Cmd[src] = INV_InvAck &&
           Dir_Pending = True && 
           Dir_InvSet[src] = True &&
           Dir_InvSet[pp] = True }
{
        InvMsg_Cmd[src] := INV_None;
        Dir_InvSet[src] := False;
}

transition ni_InvAck_exists_home (src)
requires { Sort[src] = Proc && Home <> src &&
           InvMsg_Cmd[src] = INV_InvAck &&
           Dir_Pending = True && 
           Dir_InvSet[src] = True &&
           Dir_InvSet_home = True }
{
        InvMsg_Cmd[src] := INV_None;
        Dir_InvSet[src] := False;
}

transition ni_InvAck_done_1 (src)
requires { Sort[src] = Proc && Home <> src &&
           InvMsg_Cmd[src] = INV_InvAck &&
           Dir_Pending = True && 
           Dir_InvSet[src] = True &&
           Dir_Local = True && Dir_Dirty = False &&
           Dir_InvSet_home = False &&
           forall_other p. Dir_InvSet[p] = False }
{
        InvMsg_Cmd[src] := INV_None;
        Dir_InvSet[src] := False;
        Dir_Pending := False;
        Dir_Local := False;
        Collecting := False;
}

transition ni_InvAck_done_2 (src)
requires { Sort[src] = Proc && Home <> src &&
           InvMsg_Cmd[src] = INV_InvAck &&
           Dir_Pending = True && 
           Dir_InvSet[src] = True &&
           Dir_Local = False &&
           Dir_InvSet_home = False &&
           forall_other p. Dir_InvSet[p] = False }
{
        InvMsg_Cmd[src] := INV_None;
        Dir_InvSet[src] := False;
        Dir_Pending := False;
        Collecting := False;
}

transition ni_InvAck_done_3 (src)
requires { Sort[src] = Proc && Home <> src &&
           InvMsg_Cmd[src] = INV_InvAck &&
           Dir_Pending = True && 
           Dir_InvSet[src] = True &&
           Dir_Dirty = True &&
           Dir_InvSet_home = False &&
           forall_other p. Dir_InvSet[p] = False }
{
        InvMsg_Cmd[src] := INV_None;
        Dir_InvSet[src] := False;
        Dir_Pending := False;
        Collecting := False;
}


(*--------------------------- Muphi rule NI_Wb --------------------------*)

transition ni_Wb ()
requires { WbMsg_Cmd = WB_Wb }
{
        WbMsg_Cmd := WB_None;
        Dir_Dirty := False;
        Dir_HeadVld := False;
        MemData := WbMsg_Data;
}


(*-------------------------- Muphi rule NI_FAck -------------------------*)

transition ni_FAck_dirty ()
requires { ShWbMsg_Cmd = SHWB_FAck && Dir_Dirty = True }
{
        ShWbMsg_Cmd := SHWB_None;
        Dir_Pending := False;
        Dir_HeadPtr := ShWbMsg_Proc;
}

transition ni_FAck ()
requires { ShWbMsg_Cmd = SHWB_FAck && Dir_Dirty = False }
{
        ShWbMsg_Cmd := SHWB_None;
        Dir_Pending := False;
}


(*-------------------------- Muphi rule NI_ShWb -------------------------*)

transition ni_ShWb_home ()
requires { ShWbMsg_Cmd = SHWB_ShWb && ShWbMsg_Proc = Home }
{
        ShWbMsg_Cmd := SHWB_None;
        Dir_Pending := False;
        Dir_Dirty := False;
        Dir_ShrVld := True;
        

        Dir_ShrSet_home := True;
        Dir_InvSet_home := True;

        Dir_InvSet[p] := case | _ : Dir_ShrSet[p];

        MemData := ShWbMsg_Data;
}

transition ni_ShWb ()
requires { ShWbMsg_Cmd = SHWB_ShWb && ShWbMsg_Proc <> Home }
{
        ShWbMsg_Cmd := SHWB_None;
        Dir_Pending := False;
        Dir_Dirty := False;
        Dir_ShrVld := True;
        

        Dir_ShrSet[p] := case 
                         | p = ShWbMsg_Proc : True
                         | _ : Dir_ShrSet[p];

        Dir_InvSet_home := Dir_ShrSet_home;
        Dir_InvSet[p] := case 
                         | p = ShWbMsg_Proc : True
                         | _ : Dir_ShrSet[p];

        MemData := ShWbMsg_Data;
}


(*------------------------- Muphi rule NI_Replace -----------------------*)

transition ni_Replace_shrvld (src)
requires { Sort[src] = Proc && RpMsg_Cmd[src] = RP_Replace && Dir_ShrVld = True }
{
        RpMsg_Cmd[src] := RP_None;
        Dir_ShrSet[src] := False;
        Dir_InvSet[src] := False;
}

transition ni_Replace_shrvld_home ()
requires { RpMsg_Cmd_home = RP_Replace && Dir_ShrVld = True }
{
        RpMsg_Cmd_home := RP_None;
        Dir_ShrSet_home := False;
        Dir_InvSet_home := False;
}

transition ni_Replace (src)
requires { Sort[src] = Proc && RpMsg_Cmd[src] = RP_Replace && Dir_ShrVld = False }
{
        RpMsg_Cmd[src] := RP_None;
}

transition ni_Replace_home ()
requires { RpMsg_Cmd_home = RP_Replace && Dir_ShrVld = False }
{
        RpMsg_Cmd_home := RP_None;
}

(*-----------------------------------------------------------------------*)