(*

Copyright (c) 2017, ETH Zurich
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*)

(* ######################################################################### *)
chapter "Page Table Model for a software loaded TLB"
(* ######################################################################### *)

(*<*)
theory MipsTLBPageTable
  imports Main Set MipsTLB
begin
(*>*)

text "A TLB is a cache for the translations stored in a page table. We now
      provide a formal definition for a page table model to be used in
      conjunction with the MIPS R4600 TLB model defined earlier."

(* ========================================================================= *)
section "Page Table Specification"
(* ========================================================================= *)

text "We now define the page tabe specification followed by predicates that
      ensure the validity. This page tables specification targets the
      MIPS R4600 software loaded TLB and would need to be changed if a
      different TLB model is to be used."

(* ------------------------------------------------------------------------- *)
subsection "Definition"
(* ------------------------------------------------------------------------- *)

text "Conceptually the page table store the EntryLO as defined in the MIPS
      R4600 TLB model. We therefore express the page table entry as a
      partially defined function from a VPN and ASID to an EntryLO where
      the result is undefined if either the ASID or VPN are outside of
      their valid ranges as defined by the MIPS R4600 TLB model. Note,
      we define the function to take the VPN argument before the ASID
      to handle updates using global entries as we will see later."

record MIPSPT =
  entry :: "VPN \<Rightarrow> ASID \<Rightarrow> TLBENTRYLO"

(* ------------------------------------------------------------------------- *)
subsection "Wellformed Page Table Entry"
(* ------------------------------------------------------------------------- *)

text "The MIPSPT entries are wellformed if their TLBENTRYLO is well formed.
     Thus  we say that the all entries of the TLB are wellformed if all
     corresponding TLBENTRYLO are wellformed too. Note that all entries
     in the page tables are of the smallest page size, which is 4k."

definition MIPSPT_Entries_wellformed :: "MIPSPT \<Rightarrow> bool"
  where "MIPSPT_Entries_wellformed pt =
           (\<forall>vpn as. TLBENTRYLOWellFormed ((entry pt) vpn as) MASK4K)"

(* ------------------------------------------------------------------------- *)
subsection "No Global Page Table Entries"
(* ------------------------------------------------------------------------- *)

text "We restrict the page table from having global entries. The update function
      of the page table will take care of updating all the entries for the
      different ASIDs accordingly. "

definition MIPSPT_Entries_not_global ::  "MIPSPT \<Rightarrow> bool"
  where "MIPSPT_Entries_not_global pt = (\<forall>vpn as. \<not>(g ((entry pt) vpn as)))"

(* ------------------------------------------------------------------------- *)
subsection "A Valid Page Table"
(* ------------------------------------------------------------------------- *)

text "Consequently, we define the page table to be valid, if all its entries
      are well formed as defined in the corresponding predicate and none of
      its entries are marked global."

definition MIPSPT_valid :: "MIPSPT \<Rightarrow> bool"
  where "MIPSPT_valid pt = ((MIPSPT_Entries_wellformed pt)
                              \<and> (MIPSPT_Entries_not_global pt))"

text "Therefore, a valid page table implies that for all ASID and VPN
      the stored EntryLO is well formed and not global."

lemma MIPSPT_valid_wellformed:
  "\<And>pt. MIPSPT_valid pt  \<Longrightarrow>
        \<forall>vpn as. TLBENTRYLOWellFormed ((entry pt) vpn as) MASK4K"
  by(simp add:MIPSPT_valid_def MIPSPT_Entries_wellformed_def)

lemma MIPSPT_valid_not_global:
  "\<And>pt. MIPSPT_valid pt \<Longrightarrow> \<forall>vpn as.\<not> g ((entry pt) vpn as)"
  by(simp add:MIPSPT_valid_def MIPSPT_Entries_not_global_def)

(* ========================================================================= *)
section "Page Table Operations"
(* ========================================================================= *)

text "We now define the abstract operations to initialize, read and write
      the page table as defined above and proof assertions about the semantics
      of the operations."

(* ------------------------------------------------------------------------- *)
subsection "Initialization"
(* ------------------------------------------------------------------------- *)

text "Logically, we model the initialization or creation of the page table
      similar to allocating and zeroing region of memory and thus the
      created page table will contain all NullEntryLo entries."

definition MIPSPT_create :: "MIPSPT"
  where "MIPSPT_create = \<lparr> entry = (\<lambda>_. \<lambda>_. null_entry_lo) \<rparr>"

text "Next we proof that when using the MIPSPT-create function from above,
      the resulting page table is valid. For this purpose we show first that
      all the entries are NullEntryLo and then use this lemma to show the
      validity."

lemma MIPSPT_create_all_null:
  "\<forall>vpn as. (entry (MIPSPT_create)) vpn as = null_entry_lo"
  by(auto simp:MIPSPT_create_def)

lemma MIPSPT_create_valid:
  "MIPSPT_valid (MIPSPT_create)"
  by(simp add:MIPSPT_valid_def MIPSPT_Entries_wellformed_def
              MIPSPT_create_all_null NullEntryLoWellFormed MIPSPT_create_def
              MIPSPT_Entries_not_global_def NullEntryLo_not_global)

(* ------------------------------------------------------------------------- *)
subsection "Read Operation"
(* ------------------------------------------------------------------------- *)

text "The page table read operation returns the EntryLo for the supplied
      ASID and VPN.  "

definition MIPSPT_read :: "ASID \<Rightarrow> VPN \<Rightarrow> MIPSPT \<Rightarrow> TLBENTRYLO"
  where "MIPSPT_read as vpn pt = (entry pt) vpn as"

text "The page table reads the null entry for all entries of a newly created /
      initialized page table and that those entries are wellformed if the
      page table is valid."

lemma "\<forall>vpn as. MIPSPT_read as vpn (MIPSPT_create) = null_entry_lo"
  by(auto simp:MIPSPT_read_def MIPSPT_create_def)

lemma MIPSPT_read_wellformed:
  "\<And>pt. MIPSPT_valid pt \<Longrightarrow>
    (\<forall> as vpn. TLBENTRYLOWellFormed (MIPSPT_read as vpn pt) MASK4K)"
  by(simp add:MIPSPT_valid_def MIPSPT_Entries_wellformed_def MIPSPT_read_def)

(* ------------------------------------------------------------------------- *)
subsection "Write Operation"
(* ------------------------------------------------------------------------- *)

text "The write operation updates the the entry function of the page table.
      If the entry to be written is global, then the function is updated
      for all the possible ASIDs and the entry is marked non-global."

definition MIPSPT_write :: "ASID \<Rightarrow> VPN \<Rightarrow> TLBENTRYLO \<Rightarrow> MIPSPT \<Rightarrow> MIPSPT"
  where "MIPSPT_write as vpn e pt =
   (if g e then
     \<lparr> entry = (entry pt)(
        vpn := \<lambda>_. \<lparr> pfn=(pfn e), v=(v e), d=(d e), g=False \<rparr>
       ) \<rparr>
    else
     \<lparr> entry = (entry pt)(vpn := ((entry pt) vpn)(as := e)) \<rparr> )"

text "Next we show that the write operation preserves the validity of the
      page tables if the entry to be written is well formed. "

lemma MIPSPT_write_valid:
  "\<And>pt. MIPSPT_valid pt \<and> (TLBENTRYLOWellFormed e MASK4K)
               \<Longrightarrow> MIPSPT_valid (MIPSPT_write as vpn e pt)"
  apply(simp add:MIPSPT_write_def)
  apply(cases "g e")
   apply(simp_all add:MIPSPT_valid_def MIPSPT_Entries_wellformed_def
                      MIPSPT_Entries_not_global_def)
  apply(simp add:TLBENTRYLOWellFormed_def)
  done

paragraph "Clearing of Entries"

text "When a translation is removed the page table entry has to be cleared.
      We can express this operation as a special case of the write operation
      where we write the NullEntryLo to the ASID/VPN of the page table.
      Likewise, all entries or global entries of the page table can be cleared."

definition MIPSPT_clear :: "ASID \<Rightarrow> VPN \<Rightarrow> MIPSPT \<Rightarrow> MIPSPT"
  where "MIPSPT_clear as vpn pt = (MIPSPT_write as vpn null_entry_lo pt)"

definition MIPSPT_clearglobal :: "VPN \<Rightarrow> MIPSPT \<Rightarrow> MIPSPT"
  where "MIPSPT_clearglobal vpn pt =
    \<lparr> entry = (entry pt)(vpn := \<lambda>_. null_entry_lo) \<rparr>"

definition MIPSPT_clearall :: "MIPSPT \<Rightarrow> MIPSPT"
  where "MIPSPT_clearall pt = pt \<lparr> entry := (\<lambda>_. \<lambda>_ . null_entry_lo) \<rparr>"

text "Any of the clear function above will return the NullEntryLo if
      the entry is read back again."

lemma MIPSPT_clear_is_null_entry:
  "MIPSPT_read as vpn (MIPSPT_clear as vpn pt) = null_entry_lo"
  by(auto simp:MIPSPT_read_def MIPSPT_clear_def MIPSPT_write_def
               NullEntryLo_not_global)

lemma MIPSPT_clearglobal_null_entry:
  "\<forall>as. MIPSPT_read as vpn (MIPSPT_clearglobal vpn pt) = null_entry_lo"
  by(auto simp:MIPSPT_read_def MIPSPT_clearglobal_def MIPSPT_write_def
               NullEntryLo_not_global)

lemma MIPSPT_clearall_null_entry:
  "\<forall>as vpn. MIPSPT_read as vpn (MIPSPT_clearall pt) = null_entry_lo"
  by(auto simp:MIPSPT_read_def MIPSPT_clearall_def MIPSPT_write_def
               NullEntryLo_not_global)

text "Furthermore, clearing the entire page table is equivalent to
      create or initialize a new page table."

lemma MIPSPT_clearall_is_create :
  "MIPSPT_clearall pt = MIPSPT_create"
  by(auto simp:MIPSPT_create_def MIPSPT_clearall_def)

text "Next we show for all of the clear operation variants that the, the
      resulting page table will remain valid."

lemma MIPSPT_clear_valid:
  "\<And>pt. MIPSPT_valid pt \<Longrightarrow> MIPSPT_valid (MIPSPT_clear as vpn pt)"
  by(simp add:MIPSPT_clear_def MIPSPT_write_def NullEntryLo_not_global
              MIPSPT_valid_def  MIPSPT_Entries_wellformed_def
              NullEntryLoWellFormed MIPSPT_Entries_not_global_def)

lemma MIPSPT_clearglobal_valid:
  "\<And>pt. MIPSPT_valid pt \<Longrightarrow> MIPSPT_valid (MIPSPT_clearglobal vpn pt)"
  by(auto simp:MIPSPT_clearglobal_def MIPSPT_valid_def
               MIPSPT_Entries_wellformed_def NullEntryLoWellFormed
               MIPSPT_Entries_not_global_def NullEntryLo_not_global)

lemma MIPSPT_clearall_valid :
  "\<And>pt. MIPSPT_valid pt \<Longrightarrow> MIPSPT_valid (MIPSPT_clearall pt)"
  by(auto simp:MIPSPT_clearall_def MIPSPT_valid_def
               MIPSPT_Entries_wellformed_def NullEntryLoWellFormed
               MIPSPT_Entries_not_global_def NullEntryLo_not_global)

(* ========================================================================= *)
section "Address Translation"
(* ========================================================================= *)

text "The translate function takes an  ASID and VPN and produces a set of PFN
      that the ASID-VPN-combination translates to. If the entry is marked as
      not-valid then there is no translation."

definition MIPSPT_translate :: "MIPSPT \<Rightarrow> ASID \<Rightarrow> VPN \<Rightarrow> PFN set"
  where "MIPSPT_translate pt as vpn =
      (if (v (MIPSPT_read as vpn pt)) then {(pfn (MIPSPT_read as vpn pt))}
       else {})"

text "Next we show that the translate function will always return an empty
      or a singleton  set of a particular VPN. In particular, if the entry is
      valid, then the singleton set is returned, otherwise the empty set."

lemma MIPSPT_translate_set:
  "MIPSPT_translate (MIPSPT_write as vpn e pt) as vpn \<subseteq> {(pfn e)}"
  by(auto simp add: MIPSPT_translate_def MIPSPT_write_def MIPSPT_read_def)

lemma MIPSPT_translate_set_valid:
  "\<And>e. (v e) \<Longrightarrow> MIPSPT_translate (MIPSPT_write as vpn e pt) as vpn = {(pfn e)}"
  by(auto simp add: MIPSPT_translate_def MIPSPT_write_def MIPSPT_read_def)

lemma MIPSPT_translate_set_not_valid:
  "\<And>e. \<not>(v e) \<Longrightarrow> MIPSPT_translate (MIPSPT_write as vpn e pt) as vpn = {}"
  by(auto simp add: MIPSPT_translate_def MIPSPT_write_def MIPSPT_read_def)

text "The translate function of a newly created or one of the clear operations
      will result into an empty translation for all VPN."

lemma MIPSPT_translate_create_emtpy:
  "\<forall>vpn as. MIPSPT_translate (MIPSPT_create) as vpn = {}"
  by(auto simp:MIPSPT_create_def MIPSPT_translate_def
               MIPSPT_read_def null_entry_lo_def)

lemma MIPSPT_translate_clearall_emtpy:
  "\<forall>vpn as. MIPSPT_translate (MIPSPT_clearall pt) as vpn = {}"
  by(auto simp:MIPSPT_clearall_def MIPSPT_translate_def
               MIPSPT_read_def null_entry_lo_def)

lemma MIPSPT_translate_clearglobal_emtpy:
  "\<forall>vpn as. MIPSPT_translate (MIPSPT_clearglobal vpn pt) as vpn = {}"
  by(auto simp:MIPSPT_clearglobal_def MIPSPT_translate_def MIPSPT_write_def
               MIPSPT_read_def null_entry_lo_def)

lemma MIPSPT_translate_clear_emtpy:
  "\<forall>vpn as. MIPSPT_translate (MIPSPT_clear as vpn pt) as vpn = {}"
  by(auto simp:MIPSPT_clear_def MIPSPT_translate_def MIPSPT_write_def
               MIPSPT_read_def null_entry_lo_def)

(* ========================================================================= *)
section "Creating of a TLB Entry"
(* ========================================================================= *)

text "From the page table we can now create an EntryPair for the MIPS R4600
      TLB model by combining two adjacent entries in the page table. We
      give a definition on how the TLB entry is created and then show that
      all created entries will be well formed."

(* ------------------------------------------------------------------------- *)
subsection "Maximum Number of Entries in the Page Table"
(* ------------------------------------------------------------------------- *)

text "To ensure that created MIPS TLB entries form the MIPSPT
      are well formed, we define the maximum number of entries to be the number
      of 4k pages the MIPS TLB supports to span its 1TB=256M x 4k address space.
      This is needed as the MIPS TLB defines the range of valid VPN2"

definition MIPSPT_EntriesMax :: nat
  where "MIPSPT_EntriesMax = 268435456"

text "The maximum number of entries defined above spans the 1TB VAS of the
      MIPS TLB and hence is equal to the number of 4k pages."

lemma "MIPSPT_EntriesMax * 4096 = GB 1024"
  by(auto simp:MIPSPT_EntriesMax_def GB_def)

lemma "MIPSPT_EntriesMax = page_count MASK4K"
  by(auto simp:MIPSPT_EntriesMax_def page_count_def MB_def)

(* ------------------------------------------------------------------------- *)
subsection "TLB Entry Creation"
(* ------------------------------------------------------------------------- *)

text "For a particular ASID and VPN we can create the TLB EntryPair as
      in the following definition. Because the VPN of the EntryPair needs
      to be even, we need to do a case distinction. We then create
      the TLB EntryPair based on two consecutive entries in the page table."

definition MIPSPT_mk_tlbentry :: "MIPSPT \<Rightarrow> ASID \<Rightarrow> VPN \<Rightarrow> TLBENTRY"
  where "MIPSPT_mk_tlbentry pt as vpn =
        (if (even vpn) then
            TLBENTRY.make MASK4K \<lparr> region=0, vpn2=vpn, asid=as \<rparr>
                          ((entry pt) vpn as) ((entry pt) (vpn + 1) as)
           else
            TLBENTRY.make MASK4K \<lparr> region=0, vpn2=(vpn-1), asid=as \<rparr>
                          ((entry pt) (vpn - 1) as) ((entry pt) vpn as ))"

(* ------------------------------------------------------------------------- *)
subsection "Queries on created TLB EntryPairs"
(* ------------------------------------------------------------------------- *)

text "We provide lemmas to quickly obtain the fields of a  TLB EntryPair
     created from a page table. "

paragraph "ASID"
text "The ASID is the same as the creation function was invoked with."

lemma MIPSPT_TLBENTRY_asid_is :
   "(TLBENTRYHI.asid (hi (MIPSPT_mk_tlbentry pt as vpn))) = as"
  by(auto simp:MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

paragraph "Page Mask"
text "The page mask for all entries is always 4kB."

lemma MIPSPT_TLBENTRY_mask_is:
  "(mask (MIPSPT_mk_tlbentry pt as vpn)) = MASK4K"
  by(auto simp:MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

paragraph "VPN"
text "Depending whether the VPN was odd or even, the VPN2 of the entry is either
      VPN or VPN - 1."

lemma MIPSPT_TLBENTRY_vpn2_is_even :
  "\<And>vpn as pt. even vpn \<Longrightarrow> (vpn2 (hi (MIPSPT_mk_tlbentry pt as vpn))) = vpn"
  by(simp add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

lemma MIPSPT_TLBENTRY_vpn2_is_odd :
  "\<And>vpn as pt. odd vpn
        \<Longrightarrow> (vpn2 (hi (MIPSPT_mk_tlbentry pt as vpn))) = vpn - 1"
  by(simp add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

lemma MIPSPT_TLBENTRY_vpn2_is :
  "\<And>vpn as pt. (vpn2 (hi (MIPSPT_mk_tlbentry pt as vpn))) =
          (if (even vpn) then vpn else (vpn -1 ))"
  by(simp add:MIPSPT_TLBENTRY_vpn2_is_odd MIPSPT_TLBENTRY_vpn2_is_even)

paragraph "Minimum and Maximum VPN"
text "The minimum and maximum VPN an entry can have, depends on whether
      the VPN is even or odd and can be obtained as follows."

lemma MIPSPT_TLBENTRY_Min4kVPN_even:
  "even vpn \<Longrightarrow> EntryMin4KVPN (MIPSPT_mk_tlbentry pt as vpn) = vpn"
  by(simp add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def EntryMin4KVPN_def)

lemma MIPSPT_TLBENTRY_Max4kVPN_even:
  "even vpn \<Longrightarrow> EntryMax4KVPN (MIPSPT_mk_tlbentry pt as vpn) = Suc vpn"
  by(simp add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def EntryMax4KVPN_def)

lemma MIPSPT_TLBENTRY_Min4kVPN_odd:
  "odd vpn \<Longrightarrow> EntryMin4KVPN1 (MIPSPT_mk_tlbentry pt as vpn) = vpn"
  by(simp add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def EntryMin4KVPN1_def)

paragraph "Address Range"
text "The address range that an entry covers is given by the minimum and
     maximum VPN multiplied by the page size"

lemma MIPSPT_TLBENTRY_range_even :
  "\<And>pt as vpn.  even vpn
        \<Longrightarrow> EntryRange (MIPSPT_mk_tlbentry pt as vpn)
                   = {x. vpn * 4096 \<le> x \<and> x < (vpn + 2) * 4096}"
  by(simp add:EntryRange_def EntrySize_def EntryMinVA_def EntryMaxVA_def
              MIPSPT_TLBENTRY_mask_is MIPSPT_TLBENTRY_vpn2_is_even KB_def,
              auto)

(* ------------------------------------------------------------------------- *)
subsection "The Created Entry is Well Formed"
(* ------------------------------------------------------------------------- *)

text "We must make sure that the TLB keeps valid when a created entry is
      written into the TLB. For this we need to show that a created entry
      from the page table will be well formed with respect to the MIPS
      R4600 TLB model specification. We therefore show first that the
      VPN will always be even and within valid bounds."

lemma MIPSPT_TLBENTRY_vpn2_even:
  "\<forall>vpn. (even (vpn2 (hi (MIPSPT_mk_tlbentry pt as vpn))))"
  by(auto simp:MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

lemma VPNEvenBounds:
  assumes limit: "vpn < (Suc (Suc a))"
      and even: " even vpn"
      and aeven : "even a"
    shows  "vpn \<le> a"
  proof -
    from limit have X0:
      "vpn \<le> Suc a"
      by(auto)
    also from even aeven have X2:
      "vpn \<noteq> Suc a"
      by(auto)
    also from even X0 X2 have X1:
      "vpn < (Suc a)"
      by(auto)
    with X1 show ?thesis by(auto)
  qed

lemma VPNWithinValidBounds:
  assumes bound: "vpn < MIPSPT_EntriesMax"
      and even: "even vpn "
    shows "(Suc vpn) < MIPSPT_EntriesMax"
proof -
  have aeven:
    "even MIPSPT_EntriesMax"
    by(simp add:MIPSPT_EntriesMax_def)
  with bound even aeven have X0:
    "vpn \<le> MIPSPT_EntriesMax - 2"
    by(simp add:VPNEvenBounds)
  from X0 have X1:
    "(Suc vpn) \<le> (MIPSPT_EntriesMax - 1)"
    by(auto simp:MIPSPT_EntriesMax_def)
  with X1 show ?thesis by(auto)
qed

text "Next we use the lemmas from above to show that the created EntryPair will
      have a valid EntryHi part. "

lemma MIPSPT_TLBENTRYHI_wellformed:
  "\<And>vpn as pt. MIPSPT_valid pt \<Longrightarrow> vpn < MIPSPT_EntriesMax \<Longrightarrow> ASIDValid as \<Longrightarrow>
             TLBENTRYHIWellFormed (hi (MIPSPT_mk_tlbentry pt as vpn)) MASK4K"
  by(auto simp:MIPSPT_mk_tlbentry_def TLBENTRYHIWellFormed_def TLBENTRY.make_def
               MIPSPT_valid_def VPN2Valid_def VPNMin_def VPN2Max_def MB_def
               MIPSPT_EntriesMax_def VPNEvenBounds)

text "And finally we show that the created TLB EntryPair will always be
      well formed."

lemma MIPSPT_TLBENTRY_wellformed:
   "\<And>pt vpn as. MIPSPT_valid pt \<Longrightarrow> vpn < MIPSPT_EntriesMax \<Longrightarrow> ASIDValid as
         \<Longrightarrow> TLBENTRYWellFormed ( MIPSPT_mk_tlbentry pt as vpn)"
  apply(simp add:TLBENTRYWellFormed_def)
  apply(simp add:MIPSPT_TLBENTRYHI_wellformed MIPSPT_TLBENTRY_mask_is)
  apply(simp add:MIPSPT_valid_def MIPSPT_Entries_wellformed_def)
  apply(simp add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def)
  done

(* ------------------------------------------------------------------------- *)
subsection "Entry is not Global"
(* ------------------------------------------------------------------------- *)

text "If the page table was in a valid state, then the created TLB EntryPair
      will be not global for any VPN and ASID."

lemma MIPSPT_TLBENTRY_not_global:
  "\<And>pt. MIPSPT_valid pt
          \<Longrightarrow> \<forall>vpn as. \<not>EntryIsGlobal (MIPSPT_mk_tlbentry pt as vpn)"
  by(simp add:MIPSPT_valid_def MIPSPT_Entries_not_global_def
                 EntryIsGlobal_def MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

(* ------------------------------------------------------------------------- *)
subsection "Entry Match"
(* ------------------------------------------------------------------------- *)

text "The ASID match function will always evaluate to true for a EntryPair if
      the ASID is equal to the one used for creating the TLB EntryPair."

lemma MIPSPT_TLBENTRY_asidmatch:
  "EntryASIDMatchA as  (MIPSPT_mk_tlbentry pte as vpn)"
  by(auto simp:EntryASIDMatchA_def MIPSPT_mk_tlbentry_def TLBENTRY.make_def)

lemma "\<And>as1 as2. \<forall> mpt vpn.
       as1 = as2 \<Longrightarrow>  EntryASIDMatch (MIPSPT_mk_tlbentry (pte mpt) as1 vpn)
                                     (MIPSPT_mk_tlbentry (pte mpt) as2 vpn)"
   by(simp add: EntryASIDMatch_def)

text "The EntryPair will match on the first/second half if the VPN was the
      same as used when creating the entry, and the VPN was odd or even
      respectively. "

lemma MIPSPT_TLBENTRY_match0_even :
  "even vpn \<Longrightarrow> EntryMatchVPNASID0 vpn as (MIPSPT_mk_tlbentry pt as vpn)"
  by(simp add:EntryMatchVPNASID0_def MIPSPT_mk_tlbentry_def TLBENTRY.make_def
              EntryVPNMatchV0_def EntryMin4KVPN_def EntryMin4KVPN1_def
              EntryASIDMatchA_def)

lemma MIPSPT_TLBENTRY_match1_odd :
  "odd vpn \<Longrightarrow> EntryMatchVPNASID1 vpn as (MIPSPT_mk_tlbentry pt as (vpn))"
  by(simp add:EntryMatchVPNASID1_def MIPSPT_mk_tlbentry_def TLBENTRY.make_def
              EntryASIDMatchA_def EntryVPNMatchV1_def  EntryMin4KVPN1_def
              EntryMax4KVPN_def)

text "Lastly, we show that for all ASID and VPNs there will be a match if
      the same ASID or VPN has been used to create the TLB EntryPair."

lemma MIPSPT_TLBENTRY_match :
  "EntryMatchVPNASID vpn as (MIPSPT_mk_tlbentry pt as vpn)"
  by(simp add:EntryMatchVPNASID_def MIPSPT_TLBENTRY_asidmatch EntryVPNMatchV_def
              EntryMin4KVPN_def EntryMax4KVPN_def MIPSPT_TLBENTRY_mask_is
              MIPSPT_mk_tlbentry_def TLBENTRY.make_def EntryASIDMatchA_def)

(* ------------------------------------------------------------------------- *)
subsection "Entry Equivalence"
(* ------------------------------------------------------------------------- *)

text "For two consecutive VPNs the entries are actually the same"

lemma MIPSPT_TLBENTRY_equal_odd:
  "odd vpn \<Longrightarrow> (MIPSPT_mk_tlbentry pt as vpn)
                   = (MIPSPT_mk_tlbentry pt as (vpn - 1))"
  by(simp add:MIPSPT_mk_tlbentry_def)

lemma MIPSPT_TLBENTRY_equal_even:
  "even vpn \<Longrightarrow> (MIPSPT_mk_tlbentry pt as vpn)
                   = (MIPSPT_mk_tlbentry pt as (vpn + 1))"
  by(simp add:MIPSPT_mk_tlbentry_def)

(* ------------------------------------------------------------------------- *)
subsection "Translate Function"
(* ------------------------------------------------------------------------- *)

text "We can now simplify the translate function for a created TLB entry."

lemma MIPSPT_TLBENTRY_translate_is :
  "(TLBENTRY_translate (MIPSPT_mk_tlbentry pte as vpn) as vpn) =
   (if (v ((entry pte) vpn as)) then {(pfn ((entry  pte) vpn as))} else {})"
  apply(cases "even vpn", simp_all add:TLBENTRY_translate_def MIPSPT_TLBENTRY_match)
   apply(simp_all add:MIPSPT_mk_tlbentry_def TLBENTRY.make_def EntryIsValid0_def
                      EntryIsValid1_def EntryMin4KVPN_def EntryMin4KVPN1_def)
  done

(*>*)
end
(*<*)


theory flash99Bra  imports flash99Rev

  begin
lemma onInv99:

   assumes

     b1:"r \<in> rules N" and b2:"invf=inv99 "
   shows  "invHoldForRule' s invf r (invariants   N)"
   proof -
have c1:"ex1P N (% iRule1 .  r=NI_Local_GetX_PutX1 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_GetX  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Replace  iRule1 )\<or>ex0P N (  r=NI_ShWb N )\<or>ex0P N (  r=PI_Local_GetX_GetX2 )\<or>ex0P N (  r=NI_Local_PutXAcksDone )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX7 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Nak2  iRule1 )\<or>ex0P N (  r=NI_ReplaceHomeShrVld )\<or>ex1P N (% iRule1 .  r=NI_Remote_Put  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX5 N  iRule1 )\<or>ex0P N (  r=NI_Wb )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Get  iRule1 )\<or>ex0P N (  r=PI_Local_Replace )\<or>ex1P N (% iRule1 .  r=NI_ReplaceShrVld  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Local_GetX_PutX8 N  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_InvAck_2 N  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_Get_Nak2  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=PI_Remote_Replace  iRule1 )\<or>ex0P N (  r=NI_Nak_Home )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Put2  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_InvAck_1  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX11 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX6 N  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_Get_Put2  iRule1  iRule2 )\<or>ex0P N (  r=PI_Local_Get_Put )\<or>ex0P N (  r=PI_Local_GetX_PutX1 N )\<or>ex1P N (% iRule1 .  r=NI_InvAck_1_Home  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_Get_Nak1  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Nak1  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_Nak2  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX10_home N  iRule1 )\<or>ex1P N (% iRule1 .  r=PI_Remote_Get  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_Nak3  iRule1 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Local_GetX_PutX10 N  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX2 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_Get_Put1  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_PutX  iRule1 )\<or>ex1P N (% iRule1 .  r=Store  iRule1 )\<or>ex0P N (  r=NI_FAck )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX3 N  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_PutX3 )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_GetX_PutX  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX8_home N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Put1 N  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_GetX1 )\<or>ex0P N (  r=StoreHome )\<or>ex2P N (% iRule1  iRule2 .  r=NI_Remote_GetX_Nak  iRule1  iRule2 )\<or>ex1P N (% iRule1 .  r=NI_Inv  iRule1 )\<or>ex1P N (% iRule1 .  r=PI_Remote_PutX  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_PutX4 )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX4 N  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Nak  iRule1 )\<or>ex0P N (  r=PI_Local_GetX_PutX2 N )\<or>ex0P N (  r=NI_Local_Put )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_Nak1  iRule1 )\<or>ex0P N (  r=NI_Nak_Clear )\<or>ex0P N (  r=PI_Local_PutX )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Nak3  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Remote_GetX_Nak_Home  iRule1 )\<or>ex0P N (  r=PI_Local_Get_Get )\<or>ex1P N (% iRule1 .  r=NI_Local_GetX_PutX9 N  iRule1 )\<or>ex1P N (% iRule1 .  r=PI_Remote_GetX  iRule1 )\<or>ex0P N (  r=NI_ReplaceHome )\<or>ex1P N (% iRule1 .  r=NI_Remote_GetX_PutX_Home  iRule1 )\<or>ex1P N (% iRule1 .  r=NI_Local_Get_Put3  iRule1 )"

        apply(cut_tac  b1)
        apply auto
        done      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX1 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX1 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX1 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_GetX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_GetX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_GetX  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_GetXVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Replace  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Replace  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Replace  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_ReplaceVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_ShWb N )
"

         from c1 have c2:" r= NI_ShWb N "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_ShWb N ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_ShWbVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_GetX2 )
"

         from c1 have c2:" r= PI_Local_GetX_GetX2 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_GetX_GetX2 ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_GetX_GetX2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= NI_Local_PutXAcksDone )
"

         from c1 have c2:" r= NI_Local_PutXAcksDone "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_PutXAcksDone ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_Local_PutXAcksDoneVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX7 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX7 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX7 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX7VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Nak2  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Nak2  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Nak2  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_Nak2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_ReplaceHomeShrVld )
"

         from c1 have c2:" r= NI_ReplaceHomeShrVld "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_ReplaceHomeShrVld ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_ReplaceHomeShrVldVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_Put  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_Put  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_Put  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_PutVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX5 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX5 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX5 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX5VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_Wb )
"

         from c1 have c2:" r= NI_Wb "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_Wb ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_WbVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Get  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Get  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Get  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_GetVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_Replace )
"

         from c1 have c2:" r= PI_Local_Replace "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_Replace ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_ReplaceVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_ReplaceShrVld  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_ReplaceShrVld  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_ReplaceShrVld  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_ReplaceShrVldVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Local_GetX_PutX8 N  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Local_GetX_PutX8 N  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX8 N  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX8VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_InvAck_2 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_InvAck_2 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_InvAck_2 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_InvAck_2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_Get_Nak2  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_Get_Nak2  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_Get_Nak2  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_Get_Nak2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_Replace  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_Replace  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (PI_Remote_Replace  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis PI_Remote_ReplaceVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_Nak_Home )
"

         from c1 have c2:" r= NI_Nak_Home "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_Nak_Home ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_Nak_HomeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Put2  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Put2  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Put2  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_Put2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_InvAck_1  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_InvAck_1  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_InvAck_1  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_InvAck_1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX11 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX11 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX11 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX11VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX6 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX6 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX6 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX6VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_Get_Put2  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_Get_Put2  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_Get_Put2  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_Get_Put2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_Get_Put )
"

         from c1 have c2:" r= PI_Local_Get_Put "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_Get_Put ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_Get_PutVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX1 N )
"

         from c1 have c2:" r= PI_Local_GetX_PutX1 N "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_GetX_PutX1 N ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_GetX_PutX1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_InvAck_1_Home  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_InvAck_1_Home  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_InvAck_1_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_InvAck_1_HomeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_Get_Nak1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_Get_Nak1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_Get_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_Get_Nak1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Nak1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Nak1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_Nak1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_Nak2  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_Nak2  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_Nak2  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_Nak2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX10_home N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX10_home N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX10_home N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX10_homeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_Get  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_Get  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (PI_Remote_Get  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis PI_Remote_GetVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_Nak3  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_Nak3  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_Nak3  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_Nak3VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Local_GetX_PutX10 N  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Local_GetX_PutX10 N  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX10 N  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX10VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX2 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX2 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX2 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_Get_Put1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_Get_Put1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_Get_Put1  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_Get_Put1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_PutX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_PutX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_PutX  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_PutXVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= Store  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= Store  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (Store  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis StoreVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_FAck )
"

         from c1 have c2:" r= NI_FAck "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_FAck ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_FAckVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX3 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX3 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX3 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX3VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX3 )
"

         from c1 have c2:" r= PI_Local_GetX_PutX3 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_GetX_PutX3 ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_GetX_PutX3VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_GetX_PutX  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_GetX_PutX  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_GetX_PutX  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_GetX_PutXVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX8_home N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX8_home N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX8_home N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX8_homeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Put1 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Put1 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Put1 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_Put1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_GetX1 )
"

         from c1 have c2:" r= PI_Local_GetX_GetX1 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_GetX_GetX1 ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_GetX_GetX1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= StoreHome )
"

         from c1 have c2:" r= StoreHome "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (StoreHome ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis StoreHomeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex2P N (% iRule1  iRule2 .  r= NI_Remote_GetX_Nak  iRule1  iRule2 )
"

         from c1 obtain  iRule1  iRule2  where c2:"  iRule1~=iRule2    \<and>   iRule1 \<le> N \<and>   iRule2 \<le> N \<and>  r= NI_Remote_GetX_Nak  iRule1  iRule2 "
         by (auto simp add: ex2P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_GetX_Nak  iRule1  iRule2 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_GetX_NakVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Inv  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Inv  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Inv  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_InvVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_PutX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_PutX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (PI_Remote_PutX  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis PI_Remote_PutXVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX4 )
"

         from c1 have c2:" r= PI_Local_GetX_PutX4 "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_GetX_PutX4 ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_GetX_PutX4VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX4 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX4 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX4 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX4VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Nak  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Nak  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Nak  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_NakVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_GetX_PutX2 N )
"

         from c1 have c2:" r= PI_Local_GetX_PutX2 N "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_GetX_PutX2 N ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_GetX_PutX2VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= NI_Local_Put )
"

         from c1 have c2:" r= NI_Local_Put "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Put ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_Local_PutVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_Nak1  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_Nak1  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_Nak1  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_Nak1VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_Nak_Clear )
"

         from c1 have c2:" r= NI_Nak_Clear "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_Nak_Clear ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_Nak_ClearVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex0P N (  r= PI_Local_PutX )
"

         from c1 have c2:" r= PI_Local_PutX "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_PutX ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_PutXVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Nak3  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Nak3  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Nak3  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_Nak3VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_GetX_Nak_Home  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_GetX_Nak_Home  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_GetX_Nak_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_GetX_Nak_HomeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= PI_Local_Get_Get )
"

         from c1 have c2:" r= PI_Local_Get_Get "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (PI_Local_Get_Get ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis PI_Local_Get_GetVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_GetX_PutX9 N  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_GetX_PutX9 N  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_GetX_PutX9 N  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_GetX_PutX9VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= PI_Remote_GetX  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= PI_Remote_GetX  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (PI_Remote_GetX  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis PI_Remote_GetXVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex0P N (  r= NI_ReplaceHome )
"

         from c1 have c2:" r= NI_ReplaceHome "
         by (auto simp add: ex0P_def)

         have "invHoldForRule' s (inv99 ) (NI_ReplaceHome ) (invariants N) "
            apply(cut_tac    b2 c2 )
            by (metis NI_ReplaceHomeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
	}      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Remote_GetX_PutX_Home  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Remote_GetX_PutX_Home  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Remote_GetX_PutX_Home  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Remote_GetX_PutX_HomeVsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }      moreover
        {assume c1: "ex1P N (% iRule1 .  r= NI_Local_Get_Put3  iRule1 )
"

         from c1 obtain  iRule1  where c2:"  iRule1 \<le> N \<and>  r= NI_Local_Get_Put3  iRule1 "
         by (auto simp add: ex1P_def)

         have "invHoldForRule' s (inv99 ) (NI_Local_Get_Put3  iRule1 ) (invariants N) "
            apply(cut_tac  c2  )
            by (metis NI_Local_Get_Put3VsInv99 )
          then have "invHoldForRule' s invf r (invariants N) "
            by(cut_tac c2 b2, metis)
        }ultimately show "invHoldForRule' s invf r (invariants N) "
          by blast
     qed
end


theory SepLogic_Misc
imports   DataRefinement
begin

subsection \<open>Relators\<close>

definition nrest_rel where
  nres_rel_def_internal: "nrest_rel R \<equiv> {(c,a). c \<le> \<Down>R a}"

lemma nrest_rel_def: "\<langle>R\<rangle>nrest_rel \<equiv> {(c,a). c \<le> \<Down>R a}"
  by (simp add: nres_rel_def_internal relAPP_def)

lemma nrest_relD: "(c,a)\<in>\<langle>R\<rangle>nrest_rel \<Longrightarrow> c \<le>\<Down>R a" by (simp add: nrest_rel_def)
lemma nrest_relI: "c \<le>\<Down>R a \<Longrightarrow> (c,a)\<in>\<langle>R\<rangle>nrest_rel" by (simp add: nrest_rel_def)

lemma nrest_rel_comp: "\<langle>A\<rangle>nrest_rel O \<langle>B\<rangle>nrest_rel = \<langle>A O B\<rangle>nrest_rel"
  by (auto simp: nrest_rel_def conc_fun_chain[symmetric] conc_trans)

lemma pw_nrest_rel_iff: "(a,b)\<in>\<langle>A\<rangle>nrest_rel \<longleftrightarrow> nofailT (\<Down> A b) \<longrightarrow> nofailT a \<and> (\<forall>x t. inresT a x t \<longrightarrow> inresT (\<Down> A b) x t)"
  by (simp add: pw_le_iff nrest_rel_def)

lemma param_FAIL[param]: "(FAILT,FAILT) \<in> \<langle>R\<rangle>nrest_rel"
  by (auto simp: nrest_rel_def)

lemma param_RETURN[param]:
  "(RETURNT,RETURNT) \<in> R \<rightarrow> \<langle>R\<rangle>nrest_rel"
  by (auto simp: nrest_rel_def RETURNT_refine)

lemma param_bind[param]:
  "(bindT,bindT) \<in> \<langle>Ra\<rangle>nrest_rel \<rightarrow> (Ra\<rightarrow>\<langle>Rb\<rangle>nrest_rel) \<rightarrow> \<langle>Rb\<rangle>nrest_rel"
  by (auto simp: nrest_rel_def intro: bindT_refine dest: fun_relD)

end


theory CallArityEnd2End
imports ArityTransform CoCallAnalysisImpl
begin

locale CallArityEnd2End
begin
sublocale CoCallAnalysisImpl.

lemma fresh_var_eqE[elim_format]: "fresh_var e = x \<Longrightarrow> x \<notin>  fv e"
  by (metis fresh_var_not_free)

lemma example1:
  fixes e :: exp
  fixes f g x y z :: var
  assumes Aexp_e: "\<And>a. Aexp e\<cdot>a = esing x\<cdot>(up\<cdot>a) \<squnion> esing y\<cdot>(up\<cdot>a)"
  assumes ccExp_e: "\<And>a. CCexp e\<cdot>a = \<bottom>"
  assumes [simp]: "transform 1 e = e"
  assumes "isVal e"
  assumes disj: "y \<noteq> f" "y \<noteq> g" "x \<noteq> y" "z \<noteq> f" "z \<noteq> g" "y \<noteq> x"
  assumes fresh: "atom z \<sharp> e"
  shows "transform 1 (let y be  App (Var f) g in (let x be e in (Var x))) =
         let y be (Lam [z]. App (App (Var f) g) z) in (let x be (Lam [z]. App e z) in (Var x))"
proof-
  from arg_cong[where f = edom, OF Aexp_e]
  have "x \<in> fv e" by simp (metis Aexp_edom' insert_subset)
  hence [simp]: "\<not> nonrec [(x,e)]"
    by (simp add: nonrec_def)

  from `isVal e`
  have [simp]: "thunks [(x, e)] = {}"
    by (simp add: thunks_Cons)

  have [simp]: "CCfix [(x, e)]\<cdot>(esing x\<cdot>(up\<cdot>1) \<squnion> esing y\<cdot>(up\<cdot>1), \<bottom>) = \<bottom>"
    unfolding CCfix_def
    apply (simp add: fix_bottom_iff ccBindsExtra_simp)
    apply (simp add: ccBind_eq disj ccExp_e)
    done

  have [simp]: "Afix [(x, e)]\<cdot>(esing x\<cdot>(up\<cdot>1)) = esing x\<cdot>(up\<cdot>1) \<squnion> esing y\<cdot>(up\<cdot>1)"
    unfolding Afix_def
    apply simp
    apply (rule fix_eqI)
    apply (simp add: disj Aexp_e)
    apply (case_tac "z x")
    apply (auto simp add: disj Aexp_e)
    done

  have [simp]: "Aheap [(y, App (Var f) g)] (let x be e in Var x)\<cdot>1 = esing y\<cdot>((Aexp (let x be e in Var x )\<cdot>1) y)"
    by (auto simp add:  Aheap_nonrec_simp ABind_nonrec_eq pure_fresh fresh_at_base disj)

  have [simp]: "(Aexp (let x be e in Var x)\<cdot>1) = esing y\<cdot>(up\<cdot>1)"
    by (simp add: env_restr_join disj)

  have [simp]: "Aheap [(x, e)] (Var x)\<cdot>1 = esing x\<cdot>(up\<cdot>1)"
    by (simp add: env_restr_join disj)

  have 1: "1 = inc\<cdot>0" apply (simp add: inc_def) apply transfer apply simp done

  have [simp]: "Aeta_expand 1 (App (Var f) g) = (Lam [z]. App (App (Var f) g) z)"
    apply (simp add: 1 del: exp_assn.eq_iff)
    apply (subst change_Lam_Variable[of z "fresh_var (App (Var f) g)"])
    apply (auto simp add: fresh_Pair fresh_at_base pure_fresh disj intro!: flip_fresh_fresh  elim!: fresh_var_eqE)
    done

  have [simp]: "Aeta_expand 1 e = (Lam [z]. App e z)"
    apply (simp add: 1 del: exp_assn.eq_iff)
    apply (subst change_Lam_Variable[of z "fresh_var e"])
    apply (auto simp add: fresh_Pair fresh_at_base pure_fresh disj fresh intro!: flip_fresh_fresh  elim!: fresh_var_eqE)
    done

  show ?thesis
    by (simp del: Let_eq_iff add: map_transform_Cons map_transform_Nil disj[symmetric])
qed

end
end


(*  Title:      HOL/Auth/n_moesi_lemma_invs_on_rules.thy
    Author:     Yongjian Li and Kaiqiang Duan, State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
    Copyright    2016 State Key Lab of Computer Science, Institute of Software, Chinese Academy of Sciences
*)

header{*The n_moesi Protocol Case Study*}

theory n_moesi_lemma_invs_on_rules imports n_moesi_lemma_inv__1_on_rules n_moesi_lemma_inv__2_on_rules n_moesi_lemma_inv__3_on_rules
begin
lemma invs_on_rules:
  assumes a1: "f \<in> invariants N" and a2: "r \<in> rules N"
  shows "invHoldForRule s f r (invariants N)"
  proof -
  have b1: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)\<or>
    (\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__2  p__Inv0 p__Inv2)\<or>
    (\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__3  p__Inv0 p__Inv2)"
  apply (cut_tac a1, auto) done
    moreover {
      assume c1: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__1  p__Inv0 p__Inv2)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__1_on_rules) done
    }

    moreover {
      assume c1: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__2  p__Inv0 p__Inv2)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__2_on_rules) done
    }

    moreover {
      assume c1: "(\<exists> p__Inv0 p__Inv2. p__Inv0\<le>N\<and>p__Inv2\<le>N\<and>p__Inv0~=p__Inv2\<and>f=inv__3  p__Inv0 p__Inv2)"
      have "invHoldForRule s f r (invariants N)"
      apply (cut_tac a2 c1, metis lemma_inv__3_on_rules) done
    }

  ultimately show "invHoldForRule s f r (invariants N)"
  by satx
qed

end


theory "BAN_modified_Andrew_Secure_RPC_cert_auto"
imports
  "ESPLogic"
begin

(* section:  BAN modified Andrew Secure RPC  *)

(* text:
  Modeled after the model in the SPORE library.

  Notable differences:

    1. 'succ(x)' is invertible. Hence, we just model it as a tuple ('succ',x) of
       a global constant 'succ' and the variable x.  This means that we only
       exploit the tagging properties of 'succ', but do not assume any
       information hiding.

    2. Instead of implicit typing, we are using explicit global constants to
       discern messages.

  Note that when using a bidirectional key k[A,B] instead of the
  uni-directional key k(A,B) that is different depending on the used direction
  an attack becomes possible, as agreement on the agent identities is partially
  lost. Adding the A identity in the first message fixes that flaw.
 *)

role A
where "A =
  [ Send ''1'' <| sAV ''A'',
                  PEnc <| sC ''1'', sN ''Na'' |> ( sK ''A'' ''B'' )
               |>
  , Recv ''2'' ( PEnc <| sC ''2'', <| sC ''succ'', sN ''Na'' |>, sMV ''Nb''
                      |>
                      ( sK ''A'' ''B'' )
               )
  , Send ''3'' ( PEnc <| sC ''3'', sC ''succ'', sMV ''Nb'' |>
                      ( sK ''A'' ''B'' )
               )
  , Recv ''4'' ( PEnc <| sC ''4'', sMV ''Kab'', sMV ''Nbp'', sN ''Na'' |>
                      ( sK ''A'' ''B'' )
               )
  ]"

role B
where "B =
  [ Recv ''1'' <| sMV ''A'',
                  PEnc <| sC ''1'', sMV ''Na'' |> ( PSymK ( sMV ''A'' ) ( sAV ''B'' ) )
               |>
  , Send ''2'' ( PEnc <| sC ''2'', <| sC ''succ'', sMV ''Na'' |>, sN ''Nb''
                      |>
                      ( PSymK ( sMV ''A'' ) ( sAV ''B'' ) )
               )
  , Recv ''3'' ( PEnc <| sC ''3'', sC ''succ'', sN ''Nb'' |>
                      ( PSymK ( sMV ''A'' ) ( sAV ''B'' ) )
               )
  , Send ''4'' ( PEnc <| sC ''4'', sN ''Kab'', sN ''Nbp'', sMV ''Na'' |>
                      ( PSymK ( sMV ''A'' ) ( sAV ''B'' ) )
               )
  ]"

protocol Andrew
where "Andrew = { A, B }"

locale restricted_Andrew_state = Andrew_state

type_invariant Andrew_msc_typing for Andrew
where "Andrew_msc_typing = mk_typing
  [ ((B, ''A''), (KnownT B_1))
  , ((A, ''Kab''), (SumT (KnownT A_4) (NonceT B ''Kab'')))
  , ((B, ''Na''), (SumT (KnownT B_1) (NonceT A ''Na'')))
  , ((A, ''Nb''), (SumT (KnownT A_2) (NonceT B ''Nb'')))
  , ((A, ''Nbp''), (SumT (KnownT A_4) (NonceT B ''Nbp'')))
  ]"

sublocale Andrew_state < Andrew_msc_typing_state
proof -
  have "(t,r,s) : approx Andrew_msc_typing"
  proof(cases rule: reachable_in_approxI_ext
        [OF Andrew_msc_typing.monoTyp, completeness_cases_rule])
    case (A_2_Nb t r s tid0)
    then interpret state: Andrew_msc_typing_state t r s
      by unfold_locales auto
    note_prefix_closed (state) facts = A_2_Nb
    thus ?case
    proof(sources! "
        Enc {| LC ''2'', {| LC ''succ'', LN ''Na'' tid0 |}, s(MV ''Nb'' tid0) |}
            ( K ( s(AV ''A'' tid0) ) ( s(AV ''B'' tid0) ) ) ")
    qed (safe?, simp_all?, insert facts, (((fastforce intro: event_predOrdI split: if_splits))+)?)
  next
    case (A_4_Kab t r s tid0)
    then interpret state: Andrew_msc_typing_state t r s
      by unfold_locales auto
    note_prefix_closed (state) facts = A_4_Kab
    thus ?case
    proof(sources! "
        Enc {| LC ''4'', s(MV ''Kab'' tid0), s(MV ''Nbp'' tid0), LN ''Na'' tid0
            |}
            ( K ( s(AV ''A'' tid0) ) ( s(AV ''B'' tid0) ) ) ")
    qed (safe?, simp_all?, insert facts, (((fastforce intro: event_predOrdI split: if_splits))+)?)
  next
    case (A_4_Nbp t r s tid0)
    then interpret state: Andrew_msc_typing_state t r s
      by unfold_locales auto
    note_prefix_closed (state) facts = A_4_Nbp
    thus ?case
    proof(sources! "
        Enc {| LC ''4'', s(MV ''Kab'' tid0), s(MV ''Nbp'' tid0), LN ''Na'' tid0
            |}
            ( K ( s(AV ''A'' tid0) ) ( s(AV ''B'' tid0) ) ) ")
    qed (safe?, simp_all?, insert facts, (((fastforce intro: event_predOrdI split: if_splits))+)?)
  next
    case (B_1_A t r s tid0)
    then interpret state: Andrew_msc_typing_state t r s
      by unfold_locales auto
    note_prefix_closed (state) facts = B_1_A
    thus ?case
    by (fastforce intro: event_predOrdI split: if_splits)
  next
    case (B_1_Na t r s tid0)
    then interpret state: Andrew_msc_typing_state t r s
      by unfold_locales auto
    note_prefix_closed (state) facts = B_1_Na
    thus ?case
    proof(sources! "
        Enc {| LC ''1'', s(MV ''Na'' tid0) |}
            ( K ( s(MV ''A'' tid0) ) ( s(AV ''B'' tid0) ) ) ")
    qed (safe?, simp_all?, insert facts, (((fastforce intro: event_predOrdI split: if_splits))+)?)
  qed
  thus "Andrew_msc_typing_state t r s" by unfold_locales auto
qed

text{* Prove secrecy of long-term keys. *}
context Andrew_state begin

  (* This rule is unsafe in general, but OK here,
     as we are only reasoning about static compromise.
  *)
  lemma static_longterm_key_reveal[dest!]:
    "predOrd t (LKR a) e ==> RLKR a : reveals t"
    by (auto intro: compr_predOrdI)

  lemma longterm_private_key_secrecy:
    assumes facts:
      "SK m : knows t"
      "RLKR m ~: reveals t"
    shows "False"
  using facts by (sources "SK m")

  lemma longterm_sym_ud_key_secrecy:
    assumes facts:
      "K m1 m2 : knows t"
      "RLKR m1 ~: reveals t"
      "RLKR m2 ~: reveals t"
    shows "False"
  using facts by (sources "K m1 m2")

  lemma longterm_sym_bd_key_secrecy:
    assumes facts:
      "Kbd m1 m2 : knows t"
      "RLKR m1 ~: reveals t"
      "RLKR m2 ~: reveals t"
      "m1 : Agent"
      "m2 : Agent"
    shows "False"
  proof -
    from facts
    have "KShr (agents {m1, m2}) : knows t"
      by (auto simp: Kbd_def)
    thus ?thesis using facts
    proof (sources "KShr (agents {m1, m2})")
    qed (auto simp: agents_def Agent_def)
  qed

  lemmas ltk_secrecy =
    longterm_sym_ud_key_secrecy
    longterm_sym_ud_key_secrecy[OF in_knows_predOrd1]
    longterm_sym_bd_key_secrecy
    longterm_sym_bd_key_secrecy[OF in_knows_predOrd1]
    longterm_private_key_secrecy
    longterm_private_key_secrecy[OF in_knows_predOrd1]

end

(* subsection:  Security Properties  *)

lemma (in restricted_Andrew_state) B_sec_Kab:
  assumes facts:
    "roleMap r tid0 = Some B"
    "RLKR(s(AV ''B'' tid0)) ~: reveals t"
    "RLKR(s(MV ''A'' tid0)) ~: reveals t"
    "LN ''Kab'' tid0 : knows t"
  shows "False"
using facts proof(sources! " LN ''Kab'' tid0 ")
  case B_4_Kab note_unified facts = this facts
  thus ?thesis by (auto dest!: ltk_secrecy)
qed (safe?, simp_all?, insert facts, (fastforce+)?)

lemma (in restricted_Andrew_state) A_sec_Kab:
  assumes facts:
    "roleMap r tid0 = Some A"
    "RLKR(s(AV ''A'' tid0)) ~: reveals t"
    "RLKR(s(AV ''B'' tid0)) ~: reveals t"
    "( tid0, A_4 ) : steps t"
    "s(MV ''Kab'' tid0) : knows t"
  shows "False"
proof -
  note_prefix_closed facts = facts
  thus ?thesis proof(sources! "
                   Enc {| LC ''4'', s(MV ''Kab'' tid0), s(MV ''Nbp'' tid0), LN ''Na'' tid0
                       |}
                       ( K ( s(AV ''A'' tid0) ) ( s(AV ''B'' tid0) ) ) ")
    case fake note_unified facts = this facts
    thus ?thesis by (auto dest!: ltk_secrecy)
  next
    case (B_4_enc tid1) note_unified facts = this facts
    thus ?thesis by (fastforce dest: B_sec_Kab intro: event_predOrdI)
  qed (safe?, simp_all?, insert facts, (fastforce+)?)
qed

lemma (in restricted_Andrew_state) A_noninjective_agreement:
  assumes facts:
    "roleMap r tid1 = Some A"
    "RLKR(s(AV ''A'' tid1)) ~: reveals t"
    "RLKR(s(AV ''B'' tid1)) ~: reveals t"
    "( tid1, A_4 ) : steps t"
  shows
    "(?  tid2.
        roleMap r tid2 = Some B &
        s(AV ''A'' tid1) = s(MV ''A'' tid2) &
        s(AV ''B'' tid1) = s(AV ''B'' tid2) &
        LN ''Na'' tid1 = s(MV ''Na'' tid2) &
        s(MV ''Nbp'' tid1) = LN ''Nbp'' tid2 &
        s(MV ''Kab'' tid1) = LN ''Kab'' tid2)"
proof -
  note_prefix_closed facts = facts
  thus ?thesis proof(sources! "
                   Enc {| LC ''4'', s(MV ''Kab'' tid1), s(MV ''Nbp'' tid1), LN ''Na'' tid1
                       |}
                       ( K ( s(AV ''A'' tid1) ) ( s(AV ''B'' tid1) ) ) ")
    case fake note_unified facts = this facts
    thus ?thesis by (auto dest!: ltk_secrecy)
  next
    case (B_4_enc tid2) note_unified facts = this facts
    thus ?thesis by (fastforce intro: event_predOrdI split: if_splits)
  qed (safe?, simp_all?, insert facts, (fastforce+)?)
qed

(* text:
Compared to the original Andrew_Secure_RPC protocol, the nonce Na was
added in the last exchange. This allows the modified protocol to achieve
agreement on the nonce Na which binds the responder to the session of A;
thereby fixing a freshness flaw.
 *)

lemma (in restricted_Andrew_state) B_noninjective_agreement:
  assumes facts:
    "roleMap r tid1 = Some B"
    "RLKR(s(AV ''B'' tid1)) ~: reveals t"
    "RLKR(s(MV ''A'' tid1)) ~: reveals t"
    "( tid1, B_3 ) : steps t"
  shows
    "(?  tid2.
        roleMap r tid2 = Some A &
        s(MV ''A'' tid1) = s(AV ''A'' tid2) &
        s(AV ''B'' tid1) = s(AV ''B'' tid2) &
        s(MV ''Na'' tid1) = LN ''Na'' tid2 & LN ''Nb'' tid1 = s(MV ''Nb'' tid2))"
proof -
  note_prefix_closed facts = facts
  thus ?thesis proof(sources! "
                   Enc {| LC ''3'', LC ''succ'', LN ''Nb'' tid1 |}
                       ( K ( s(MV ''A'' tid1) ) ( s(AV ''B'' tid1) ) ) ")
    case fake note_unified facts = this facts
    thus ?thesis by (auto dest!: ltk_secrecy)
  next
    case (A_3_enc tid2) note_unified facts = this facts
    thus ?thesis proof(sources! "
                     Enc {| LC ''2'', {| LC ''succ'', LN ''Na'' tid2 |}, LN ''Nb'' tid1 |}
                         ( K ( s(AV ''A'' tid2) ) ( s(AV ''B'' tid1) ) ) ")
      case fake note_unified facts = this facts
      thus ?thesis by (auto dest!: ltk_secrecy)
    next
      case (B_2_enc tid3) note_unified facts = this facts
      thus ?thesis by (fastforce intro: event_predOrdI split: if_splits)
    qed (safe?, simp_all?, insert facts, (fastforce+)?)
  qed (safe?, simp_all?, insert facts, (fastforce+)?)
qed

(* text:
The protocol does not achieve agreement on the key because B cannot check if it
has been received.
 *)

end