(*  Title:      Jinja/J/WellForm.thy

    Author:     Tobias Nipkow
    Copyright   2003 Technische Universitaet Muenchen
*)

header {* \isaheader{Generic Well-formedness of programs} *}

theory WellForm imports TypeRel SystemClasses begin

text {*\noindent This theory defines global well-formedness conditions
for programs but does not look inside method bodies.  Hence it works
for both Jinja and JVM programs. Well-typing of expressions is defined
elsewhere (in theory @{text WellType}).

Because Jinja does not have method overloading, its policy for method
overriding is the classical one: \emph{covariant in the result type
but contravariant in the argument types.} This means the result type
of the overriding method becomes more specific, the argument types
become more general.
*}

type_synonym 'm wf_mdecl_test = "'m prog \<Rightarrow> cname \<Rightarrow> 'm mdecl \<Rightarrow> bool"

definition wf_fdecl :: "'m prog \<Rightarrow> fdecl \<Rightarrow> bool"
where
  "wf_fdecl P \<equiv> \<lambda>(F,T). is_type P T"

definition wf_mdecl :: "'m wf_mdecl_test \<Rightarrow> 'm wf_mdecl_test"
where
  "wf_mdecl wf_md P C \<equiv> \<lambda>(M,Ts,T,mb).
  (\<forall>T\<in>set Ts. is_type P T) \<and> is_type P T \<and> wf_md P C (M,Ts,T,mb)"

definition wf_cdecl :: "'m wf_mdecl_test \<Rightarrow> 'm prog \<Rightarrow> 'm cdecl \<Rightarrow> bool"
where
  "wf_cdecl wf_md P  \<equiv>  \<lambda>(C,(D,fs,ms)).
  (\<forall>f\<in>set fs. wf_fdecl P f) \<and>  distinct_fst fs \<and>
  (\<forall>m\<in>set ms. wf_mdecl wf_md P C m) \<and>  distinct_fst ms \<and>
  (C \<noteq> Object \<longrightarrow>
   is_class P D \<and> \<not> P \<turnstile> D \<preceq>\<^sup>* C \<and>
   (\<forall>(M,Ts,T,m)\<in>set ms.
      \<forall>D' Ts' T' m'. P \<turnstile> D sees M:Ts' \<rightarrow> T' = m' in D' \<longrightarrow>
                       P \<turnstile> Ts' [\<le>] Ts \<and> P \<turnstile> T \<le> T'))"

definition wf_syscls :: "'m prog \<Rightarrow> bool"
where
  "wf_syscls P  \<equiv>  {Object} \<union> sys_xcpts \<subseteq> set(map fst P)"

definition wf_prog :: "'m wf_mdecl_test \<Rightarrow> 'm prog \<Rightarrow> bool"
where
  "wf_prog wf_md P  \<equiv>  wf_syscls P \<and> (\<forall>c \<in> set P. wf_cdecl wf_md P c) \<and> distinct_fst P"

subsection{* Well-formedness lemmas *}

lemma class_wf:
  "\<lbrakk>class P C = Some c; wf_prog wf_md P\<rbrakk> \<Longrightarrow> wf_cdecl wf_md P (C,c)"
(*<*)
apply (unfold wf_prog_def class_def)
apply (fast dest: map_of_SomeD)
done
(*>*)

lemma class_Object [simp]:
  "wf_prog wf_md P \<Longrightarrow> \<exists>C fs ms. class P Object = Some (C,fs,ms)"
(*<*)
apply (unfold wf_prog_def wf_syscls_def class_def)
apply (auto simp: map_of_SomeI)
done
(*>*)

lemma is_class_Object [simp]:
  "wf_prog wf_md P \<Longrightarrow> is_class P Object"
(*<*)by (simp add: is_class_def)(*>*)
(* Unused
lemma is_class_supclass:
assumes wf: "wf_prog wf_md P" and sub: "P \<turnstile> C \<preceq>\<^sup>* D"
shows "is_class P C \<Longrightarrow> is_class P D"
using sub apply(induct)
 apply assumption
apply(fastforce simp:wf_cdecl_def subcls1_def is_class_def
               dest:class_wf[OF _ wf])
done

This is NOT true because P \<turnstile> NT \<le> Class C for any Class C
lemma is_type_suptype: "\<lbrakk> wf_prog p P; is_type P T; P \<turnstile> T \<le> T' \<rbrakk>
 \<Longrightarrow> is_type P T'"
*)

lemma is_class_xcpt:
  "\<lbrakk> C \<in> sys_xcpts; wf_prog wf_md P \<rbrakk> \<Longrightarrow> is_class P C"
(*<*)
  apply (simp add: wf_prog_def wf_syscls_def is_class_def class_def)
  apply (fastforce intro!: map_of_SomeI)
  done
(*>*)

lemma subcls1_wfD:
  "\<lbrakk> P \<turnstile> C \<prec>\<^sup>1 D; wf_prog wf_md P \<rbrakk> \<Longrightarrow> D \<noteq> C \<and> (D,C) \<notin> (subcls1 P)\<^sup>+"
(*<*)
apply( frule r_into_trancl)
apply( drule subcls1D)
apply(clarify)
apply( drule (1) class_wf)
apply( unfold wf_cdecl_def)
apply(force simp add: reflcl_trancl [THEN sym] simp del: reflcl_trancl)
done
(*>*)

lemma wf_cdecl_supD:
  "\<lbrakk>wf_cdecl wf_md P (C,D,r); C \<noteq> Object\<rbrakk> \<Longrightarrow> is_class P D"
(*<*)by (auto simp: wf_cdecl_def)(*>*)

lemma subcls_asym:
  "\<lbrakk> wf_prog wf_md P; (C,D) \<in> (subcls1 P)\<^sup>+ \<rbrakk> \<Longrightarrow> (D,C) \<notin> (subcls1 P)\<^sup>+"
(*<*)
apply(erule tranclE)
apply(fast dest!: subcls1_wfD )
apply(fast dest!: subcls1_wfD intro: trancl_trans)
done
(*>*)

lemma subcls_irrefl:
  "\<lbrakk> wf_prog wf_md P; (C,D) \<in> (subcls1 P)\<^sup>+ \<rbrakk> \<Longrightarrow> C \<noteq> D"
(*<*)
apply (erule trancl_trans_induct)
apply  (auto dest: subcls1_wfD subcls_asym)
done
(*>*)

lemma acyclic_subcls1:
  "wf_prog wf_md P \<Longrightarrow> acyclic (subcls1 P)"
(*<*)
apply (unfold acyclic_def)
apply (fast dest: subcls_irrefl)
done
(*>*)

lemma wf_subcls1:
  "wf_prog wf_md P \<Longrightarrow> wf ((subcls1 P)\<inverse>)"
(*<*)
apply (rule finite_acyclic_wf)
apply ( subst finite_converse)
apply ( rule finite_subcls1)
apply (subst acyclic_converse)
apply (erule acyclic_subcls1)
done
(*>*)

lemma single_valued_subcls1:
  "wf_prog wf_md G \<Longrightarrow> single_valued (subcls1 G)"
(*<*)
by(auto simp:wf_prog_def distinct_fst_def single_valued_def dest!:subcls1D)
(*>*)

lemma subcls_induct:
  "\<lbrakk> wf_prog wf_md P; \<And>C. \<forall>D. (C,D) \<in> (subcls1 P)\<^sup>+ \<longrightarrow> Q D \<Longrightarrow> Q C \<rbrakk> \<Longrightarrow> Q C"
(*<*)
  (is "?A \<Longrightarrow> PROP ?P \<Longrightarrow> _")
proof -
  assume p: "PROP ?P"
  assume ?A thus ?thesis apply -
apply(drule wf_subcls1)
apply(drule wf_trancl)
apply(simp only: trancl_converse)
apply(erule_tac a = C in wf_induct)
apply(rule p)
apply(auto)
done
qed
(*>*)

lemma subcls1_induct_aux:
  "\<lbrakk> is_class P C; wf_prog wf_md P; Q Object;
    \<And>C D fs ms.
    \<lbrakk> C \<noteq> Object; is_class P C; class P C = Some (D,fs,ms) \<and>
      wf_cdecl wf_md P (C,D,fs,ms) \<and> P \<turnstile> C \<prec>\<^sup>1 D \<and> is_class P D \<and> Q D\<rbrakk> \<Longrightarrow> Q C \<rbrakk>
  \<Longrightarrow> Q C"
(*<*)
  (is "?A \<Longrightarrow> ?B \<Longrightarrow> ?C \<Longrightarrow> PROP ?P \<Longrightarrow> _")
proof -
  assume p: "PROP ?P"
  assume ?A ?B ?C thus ?thesis apply -
apply(unfold is_class_def)
apply( rule impE)
prefer 2
apply(   assumption)
prefer 2
apply(  assumption)
apply( erule thin_rl)
apply( rule subcls_induct)
apply(  assumption)
apply( rule impI)
apply( case_tac "C = Object")
apply(  fast)
apply safe
apply( frule (1) class_wf)
apply( frule (1) wf_cdecl_supD)

apply( subgoal_tac "P \<turnstile> C \<prec>\<^sup>1 a")
apply( erule_tac [2] subcls1I)
apply(  rule p)
apply (unfold is_class_def)
apply auto
done
qed
(*>*)

(* FIXME can't we prove this one directly?? *)
lemma subcls1_induct [consumes 2, case_names Object Subcls]:
  "\<lbrakk> wf_prog wf_md P; is_class P C; Q Object;
    \<And>C D. \<lbrakk>C \<noteq> Object; P \<turnstile> C \<prec>\<^sup>1 D; is_class P D; Q D\<rbrakk> \<Longrightarrow> Q C \<rbrakk>
  \<Longrightarrow> Q C"
(*<*)
  apply (erule subcls1_induct_aux, assumption, assumption)
  apply blast
  done
(*>*)

lemma subcls_C_Object:
  "\<lbrakk> is_class P C; wf_prog wf_md P \<rbrakk> \<Longrightarrow> P \<turnstile> C \<preceq>\<^sup>* Object"
(*<*)
apply(erule (1) subcls1_induct)
 apply( fast)
apply(erule (1) converse_rtrancl_into_rtrancl)
done
(*>*)

lemma is_type_pTs:
assumes "wf_prog wf_md P" and "(C,S,fs,ms) \<in> set P" and "(M,Ts,T,m) \<in> set ms"
shows "set Ts \<subseteq> types P"
(*<*)
proof
  from assms have "wf_mdecl wf_md P C (M,Ts,T,m)"
    by (unfold wf_prog_def wf_cdecl_def) auto
  hence "\<forall>t \<in> set Ts. is_type P t" by (unfold wf_mdecl_def) auto
  moreover fix t assume "t \<in> set Ts"
  ultimately have "is_type P t" by blast
  thus "t \<in> types P" ..
qed
(*>*)

subsection{* Well-formedness and method lookup *}

lemma sees_wf_mdecl:
  "\<lbrakk> wf_prog wf_md P; P \<turnstile> C sees M:Ts\<rightarrow>T = m in D \<rbrakk> \<Longrightarrow> wf_mdecl wf_md P D (M,Ts,T,m)"
(*<*)
apply(drule visible_method_exists)
apply(fastforce simp:wf_cdecl_def dest!:class_wf dest:map_of_SomeD)
done
(*>*)

lemma sees_method_mono [rule_format (no_asm)]:
  "\<lbrakk> P \<turnstile> C' \<preceq>\<^sup>* C; wf_prog wf_md P \<rbrakk> \<Longrightarrow>
  \<forall>D Ts T m. P \<turnstile> C sees M:Ts\<rightarrow>T = m in D \<longrightarrow>
     (\<exists>D' Ts' T' m'. P \<turnstile> C' sees M:Ts'\<rightarrow>T' = m' in D' \<and> P \<turnstile> Ts [\<le>] Ts' \<and> P \<turnstile> T' \<le> T)"
(*<*)
apply( drule rtranclD)
apply( erule disjE)
apply(  fastforce)
apply( erule conjE)
apply( erule trancl_trans_induct)
prefer 2
apply(  clarify)
apply(  drule spec, drule spec, drule spec, drule spec, erule (1) impE)
apply clarify
apply(  fast elim: widen_trans widens_trans)
apply( clarify)
apply( drule subcls1D)
apply( clarify)
apply(clarsimp simp:Method_def)
apply(frule (2) sees_methods_rec)
apply(rule refl)
apply(case_tac "map_of ms M")
apply(rule_tac x = D in exI)
apply(rule_tac x = Ts in exI)
apply(rule_tac x = T in exI)
apply simp
apply(rule_tac x = m in exI)
apply(fastforce simp add:map_add_def split:option.split)
apply clarsimp
apply(rename_tac Ts' T' m')
apply( drule (1) class_wf)
apply( unfold wf_cdecl_def Method_def)
apply( frule map_of_SomeD)
apply auto
apply(drule (1) bspec, simp)
apply(erule_tac x=D in allE, erule_tac x=Ts in allE, erule_tac x=T in allE)
apply(fastforce simp:map_add_def split:option.split)
done
(*>*)

lemma sees_method_mono2:
  "\<lbrakk> P \<turnstile> C' \<preceq>\<^sup>* C; wf_prog wf_md P;
     P \<turnstile> C sees M:Ts\<rightarrow>T = m in D; P \<turnstile> C' sees M:Ts'\<rightarrow>T' = m' in D' \<rbrakk>
  \<Longrightarrow> P \<turnstile> Ts [\<le>] Ts' \<and> P \<turnstile> T' \<le> T"
(*<*)by(blast dest:sees_method_mono sees_method_fun)(*>*)

lemma mdecls_visible:
assumes wf: "wf_prog wf_md P" and "class": "is_class P C"
shows "\<And>D fs ms. class P C = Some(D,fs,ms)
         \<Longrightarrow> \<exists>Mm. P \<turnstile> C sees_methods Mm \<and> (\<forall>(M,Ts,T,m) \<in> set ms. Mm M = Some((Ts,T,m),C))"
(*<*)
using wf "class"
proof (induct rule:subcls1_induct)
  case Object
  with wf have "distinct_fst ms"
    by (unfold class_def wf_prog_def wf_cdecl_def) (fastforce dest:map_of_SomeD)
  with Object show ?case by(fastforce intro!: sees_methods_Object map_of_SomeI)
next
  case Subcls
  with wf have "distinct_fst ms"
    by (unfold class_def wf_prog_def wf_cdecl_def) (fastforce dest:map_of_SomeD)
  with Subcls show ?case
    by(fastforce elim:sees_methods_rec dest:subcls1D map_of_SomeI
                simp:is_class_def)
qed
(*>*)

lemma mdecl_visible:
assumes wf: "wf_prog wf_md P" and C: "(C,S,fs,ms) \<in> set P" and  m: "(M,Ts,T,m) \<in> set ms"
shows "P \<turnstile> C sees M:Ts\<rightarrow>T = m in C"
(*<*)
proof -
  from wf C have "class": "class P C = Some (S,fs,ms)"
    by (auto simp add: wf_prog_def class_def is_class_def intro: map_of_SomeI)
  from "class" have "is_class P C" by(auto simp:is_class_def)
  with assms "class" show ?thesis
    by(bestsimp simp:Method_def dest:mdecls_visible)
qed
(*>*)

lemma Call_lemma:
  "\<lbrakk> P \<turnstile> C sees M:Ts\<rightarrow>T = m in D; P \<turnstile> C' \<preceq>\<^sup>* C; wf_prog wf_md P \<rbrakk>
  \<Longrightarrow> \<exists>D' Ts' T' m'.
       P \<turnstile> C' sees M:Ts'\<rightarrow>T' = m' in D' \<and> P \<turnstile> Ts [\<le>] Ts' \<and> P \<turnstile> T' \<le> T \<and> P \<turnstile> C' \<preceq>\<^sup>* D'
       \<and> is_type P T' \<and> (\<forall>T\<in>set Ts'. is_type P T) \<and> wf_md P D' (M,Ts',T',m')"
(*<*)
apply(frule (2) sees_method_mono)
apply(fastforce intro:sees_method_decl_above dest:sees_wf_mdecl
               simp: wf_mdecl_def)
done
(*>*)

lemma wf_prog_lift:
  assumes wf: "wf_prog (\<lambda>P C bd. A P C bd) P"
  and rule:
  "\<And>wf_md C M Ts C T m bd.
   wf_prog wf_md P \<Longrightarrow>
   P \<turnstile> C sees M:Ts\<rightarrow>T = m in C \<Longrightarrow>
   set Ts \<subseteq>  types P \<Longrightarrow>
   bd = (M,Ts,T,m) \<Longrightarrow>
   A P C bd \<Longrightarrow>
   B P C bd"
  shows "wf_prog (\<lambda>P C bd. B P C bd) P"
(*<*)
proof -
  from wf show ?thesis
    apply (unfold wf_prog_def wf_cdecl_def)
    apply clarsimp
    apply (drule bspec, assumption)
    apply (unfold wf_mdecl_def)
    apply clarsimp
    apply (drule bspec, assumption)
    apply clarsimp
    apply (frule mdecl_visible [OF wf], assumption+)
    apply (frule is_type_pTs [OF wf], assumption+)
    apply (drule rule [OF wf], assumption+)
    apply auto
    done
qed
(*>*)

subsection{* Well-formedness and field lookup *}

lemma wf_Fields_Ex:
  "\<lbrakk> wf_prog wf_md P; is_class P C \<rbrakk> \<Longrightarrow> \<exists>FDTs. P \<turnstile> C has_fields FDTs"
(*<*)
apply(frule class_Object)
apply(erule (1) subcls1_induct)
 apply(blast intro:has_fields_Object)
apply(blast intro:has_fields_rec dest:subcls1D)
done
(*>*)

lemma has_fields_types:
  "\<lbrakk> P \<turnstile> C has_fields FDTs; (FD,T) \<in> set FDTs; wf_prog wf_md P \<rbrakk> \<Longrightarrow> is_type P T"
(*<*)
apply(induct rule:Fields.induct)
 apply(fastforce dest!: class_wf simp: wf_cdecl_def wf_fdecl_def)
apply(fastforce dest!: class_wf simp: wf_cdecl_def wf_fdecl_def)
done
(*>*)

lemma sees_field_is_type:
  "\<lbrakk> P \<turnstile> C sees F:T in D; wf_prog wf_md P \<rbrakk> \<Longrightarrow> is_type P T"
(*<*)
by(fastforce simp: sees_field_def
            elim: has_fields_types map_of_SomeD[OF map_of_remap_SomeD])
(*>*)

lemma wf_syscls:
  "set SystemClasses \<subseteq> set P \<Longrightarrow> wf_syscls P"
(*<*)
apply (simp add: image_def SystemClasses_def wf_syscls_def sys_xcpts_def
                 ObjectC_def NullPointerC_def ClassCastC_def OutOfMemoryC_def)
 apply force
done
(*>*)

end


theory ARMv7A_Update_ASID_Ref

imports  ARMv7A_Update_TTBR0_Ref

begin

lemma  update_asid_non_det_sat_refine:
  "\<lbrakk> update_ASID a (s::'a non_det_tlb_state_scheme) = ((), s') ;  update_ASID a (t::'b sat_tlb_state_scheme) = ((), t');
         tlb_rel_sat (typ_non_det_tlb s) (typ_sat_tlb t) \<rbrakk> \<Longrightarrow>
                  tlb_rel_sat (typ_non_det_tlb s') (typ_sat_tlb t')"
  apply (clarsimp simp: update_ASID_non_det_tlb_state_ext_def update_ASID_sat_tlb_state_ext_def)
  apply (clarsimp simp: tlb_rel_sat_def saturated_def)
  apply (cases s, cases t , clarsimp simp: state.defs pairsub_def, force)
  done

lemma asid_unequal_snp_upd_equal' [simp]:
  "a \<noteq> a' \<Longrightarrow>   snp_upd_cur' snp ist m r a' a = snp a"
  by (clarsimp simp: snp_upd_cur'_def)

lemma saturated_global_subset_lookup_tlb_un_eq:
  "saturated (typ_sat_tlb s) \<Longrightarrow>
        lookup''(global_entries (fst(sat_tlb s)) \<union>
                 global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))  a v =
                 lookup'' (global_entries (fst(sat_tlb s))) a v"
  apply (rule tlb_subset_lookup_un_eq)
  apply (subgoal_tac "global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) =
                       global_entries (the ` {e \<in> range (pt_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e})")
   apply (simp only:)
   apply (clarsimp simp: saturated_def global_entries_def) apply blast
  by (rule global_entries_ptable_same)

lemma saturated_global_subset_lookup_pdc_un_eq:
  "saturated (typ_sat_tlb s) \<Longrightarrow>
        lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union>
                 global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))  a v =
                 lookup_pdc (global_entries_pdc (snd(sat_tlb s))) a v"
  apply (rule pdc_subset_lookup_un_eq)
  apply (subgoal_tac "global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) =
                       global_entries_pdc (the ` {e \<in> range (pdc_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e})")
   apply (simp only:)
   apply (clarsimp simp: saturated_def global_entries_pdc_def) apply blast
  by (rule global_entries_pdc_ptable_same)

lemma  update_asid_sat_incon_refine:
  "\<lbrakk> update_ASID a (s::'a sat_tlb_state_scheme) = ((), s') ;  update_ASID a (t::'b set_tlb_state_scheme) = ((), t');
         tlb_rel_abs (typ_sat_tlb s) (typ_set_tlb t) \<rbrakk> \<Longrightarrow>
                  tlb_rel_abs (typ_sat_tlb s') (typ_set_tlb t')"
  apply (clarsimp simp: update_ASID_sat_tlb_state_ext_def update_ASID_set_tlb_state_ext_def Let_def)
  apply (frule tlb_rel_absD)
  apply (case_tac "a = ASID s")
    (* to the same ASID *)
   apply (subgoal_tac "sat_tlb s = pairunion (sat_tlb s)
           (the ` {e \<in> range (pt_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e}, the ` {e \<in> range (pdc_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e})")
    prefer 2
    apply (clarsimp simp:  saturated_def)
   apply (clarsimp simp: tlb_rel_abs_def)
   apply (rule conjI)
    apply (clarsimp simp: state.defs)
   apply (rule conjI)
    apply clarsimp
    apply (clarsimp simp:  snp_upd_cur'_def snp_upd_cur_def )
    apply (cases t, cases s, clarsimp) apply force
   apply clarsimp
   apply (clarsimp simp: lookup_from'_def snap_conv'_def snp_upd_cur'_def snp_upd_cur_def)
    (* to new asid *)
  apply (clarsimp simp: tlb_rel_abs_def)
  apply (rule conjI)
   apply (clarsimp simp: state.defs)
  apply (rule conjI)
   apply (clarsimp simp: saturated_def)
  apply (thin_tac "s' = s \<lparr>ASID := a,    sat_tlb :=  pairunion (sat_tlb s)
                  (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}, the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})\<rparr>")
  apply (thin_tac "t' = t
     \<lparr>ASID := a,
        set_tlb := set_tlb t
          \<lparr>snapshot := snp_upd_cur' (snapshot (set_tlb t)) (iset (set_tlb t)) (MEM s) (TTBR0 s) (ASID s),
             iset := fst (snapshot (set_tlb t) a) \<union> iset (set_tlb t) \<inter> global_set (set_tlb t) \<union> ptable_comp (snd (snapshot (set_tlb t) a)) (pt_walk_pair a (MEM s) (TTBR0 s))\<rparr>\<rparr>")
  apply (rule conjI)
   apply (clarsimp simp: incon_addrs_def)
   apply (rule conjI)
    apply (clarsimp simp: inconsistent_vaddrs_def)
    apply (rule conjI)
     apply (clarsimp)
     apply (rename_tac v)
     apply (subgoal_tac "fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =  (non_global_entries (fst(sat_tlb s)) \<union> non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>
                          (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
      apply (simp only:)
      apply (thin_tac "fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =  (non_global_entries (fst(sat_tlb s)) \<union> non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>
                          (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
      apply (subgoal_tac "lookup''   (global_entries (fst(sat_tlb s)))  a v = lookup'' (global_entries (fst(sat_tlb s)) \<union>  global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v ")
       prefer 2
       apply (rule saturated_global_subset_lookup_tlb_un_eq[symmetric], simp)
      apply (drule_tac t = "non_global_entries (fst(sat_tlb s)) \<union> non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})" in union_asid_tlb_incon_cases)
      apply (erule disjE, clarsimp)
       apply (thin_tac "lookup'' (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))
                       a v =  Incon")
       apply (subgoal_tac "v \<in> iset (set_tlb t)")
        apply (subgoal_tac "v \<in> global_set (set_tlb t)")
         apply blast
        apply (clarsimp simp: global_entries_def lookup_def tagged_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
        apply blast
       apply (drule_tac a' = "ASID s" in lookup_global_incon_incon)
       apply blast
      apply (erule disjE, clarsimp)
       apply (thin_tac "lookup'' (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Hit xa")
       apply (case_tac "v \<in> global_set (set_tlb t)")
        apply (case_tac "v \<in> iset (set_tlb t)")
         apply blast
        apply clarsimp
        apply (subgoal_tac "lookup''  (fst(sat_tlb s)) (ASID s) v = Hit xa \<or>
                           lookup''  (fst(sat_tlb s)) (ASID s) v = Incon")
         apply (erule_tac P = "lookup''  (fst(sat_tlb s)) (ASID s) v = Hit xa" in disjE)
          apply (case_tac "is_fault (pt_walk (ASID s) (MEM s) (TTBR0 s) v)")
           apply (clarsimp simp: incoherrent_vaddrs_def)
           apply force
          apply (drule  lookup_asid_tlb_hit_union_cases')
          apply (erule disjE, clarsimp)
           apply (subgoal_tac "asid_of (the (pt_walk a (MEM s) (TTBR0 s) v)) = None")
            apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
            apply (clarsimp simp: non_global_to_global [symmetric])
            apply (case_tac "fst(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
             apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
            apply (drule_tac a' = a in no_fault_pt_walk_unequal_asid')
            apply (frule non_fault_pt_walk_full_walk)
            apply (subgoal_tac "the (pt_walk a (MEM s) (TTBR0 s) v) \<noteq> x3")
             apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
             apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
            apply (subgoal_tac "asid_of x3 \<noteq> None")
             apply force
            apply (drule lookup_non_global_hit_asid_of_not_none, simp)
           apply (drule lookup_non_global_miss_non_fault)
            apply (frule_tac a' = a in no_fault_pt_walk_unequal_asid', simp)
           apply (rule_tac v = v and a = a and t = "(the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})" in lookup_global_hit_asid_of_none, simp)
          apply (erule disjE, clarsimp)
           apply (subgoal_tac "xa \<noteq> the (pt_walk (ASID t) (MEM s) (TTBR0 s) v)")
            apply (drule_tac b = v and x = xa in saturatd_lookup_hit_no_fault; simp?)
           apply (subgoal_tac "asid_of xa = None")
            apply (subgoal_tac "asid_of (the (pt_walk (ASID t) (MEM s) (TTBR0 s) v)) \<noteq> None")
             apply force
            apply (subgoal_tac "lookup'' (non_global_entries (the ` {e \<in> range (pt_walk (ASID t) (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID t) v = Hit
                              (the (pt_walk (ASID t) (MEM s) (TTBR0 s) v))")
             apply (rule lookup_non_global_hit_asid_of_not_none, simp)
            apply (rule_tac a = a in non_global_lookup_hit_asid, simp)
           apply (rule lookup_global_hit_asid_of_none, simp)
          apply (clarsimp)
          apply (subgoal_tac "xa \<noteq> the (pt_walk (ASID t) (MEM s) (TTBR0 s) v)")
           apply (drule_tac b = v and x = xa in saturatd_lookup_hit_no_fault; simp?)
          apply (subgoal_tac "asid_of xa = None")
           apply (subgoal_tac "asid_of (the (pt_walk (ASID t) (MEM s) (TTBR0 s) v)) \<noteq> None")
            apply force
           apply (subgoal_tac "lookup'' (non_global_entries (the ` {e \<in> range (pt_walk (ASID t) (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID t) v = Hit
                              (the (pt_walk (ASID t) (MEM s) (TTBR0 s) v))")
            apply (rule lookup_non_global_hit_asid_of_not_none, simp)
           apply (rule_tac a = a in non_global_lookup_hit_asid, simp)
          apply (rule lookup_global_hit_asid_of_none, simp)
         apply blast
        apply (metis (no_types, hide_lams) lookup_global_hit_order lookup_global_same_for_asids)
       apply (subgoal_tac "xa \<in> global_entries (fst(sat_tlb s))")
        apply (subgoal_tac "v \<in> range_of xa")
         apply (clarsimp simp: global_range_def)
         apply blast
        apply (simp add: lookup_asid_tlb_hit_entry_range)
  using lookup_in_asid_tlb apply auto[1]
      apply (erule disjE, clarsimp)
       apply (thin_tac "lookup'' (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))
                       a v =  Incon")
       apply (subgoal_tac "v \<in> iset (set_tlb t)")
        apply (subgoal_tac "v \<in> global_set (set_tlb t)")
         apply blast
        apply (clarsimp simp: global_entries_def lookup_def tagged_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
        apply blast
       apply (drule_tac a' = "ASID s" in lookup_global_incon_incon)
       apply blast
      apply (erule disjE, clarsimp)
       apply (thin_tac "lookup'' (global_entries (fst(sat_tlb s)) \<union>  global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))a v = Hit x")
       apply (drule union_asid_tlb_incon_cases)
       apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pt_walk_not_incon apply force
       apply (erule disjE, clarsimp simp: )
        apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
        apply (clarsimp simp: non_global_to_global [symmetric])
        apply (case_tac "fst(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
         apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
        apply (subgoal_tac "\<not>is_fault (pt_walk a (MEM s) (TTBR0 s) v)")
         apply (subgoal_tac "xb = the (pt_walk a (MEM s) (TTBR0 s) v)")
          apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
          apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
          apply (metis pt_walk_new_no_fault_pt_walk' option.inject)
         apply (frule_tac a' = a in non_global_lookup_hit_asid, simp)
        apply (rule non_global_hit_no_fault, simp)
       apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pt_walk_not_incon apply force
       apply (erule disjE, clarsimp simp: )
        apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
        apply (clarsimp simp: non_global_to_global [symmetric])
        apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
       apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pt_walk_not_incon apply force
       apply (clarsimp simp: )
       apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
       apply (clarsimp simp: non_global_to_global [symmetric])
       apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
      apply (erule disjE, clarsimp)
       apply (thin_tac "lookup'' (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))
                       a v =  Incon")
       apply (subgoal_tac "v \<in> iset (set_tlb t)")
        apply (subgoal_tac "v \<in> global_set (set_tlb t)")
         apply blast
        apply (clarsimp simp: global_entries_def lookup_def tagged_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
        apply blast
       apply (drule_tac a' = "ASID s" in lookup_global_incon_incon)
       apply blast
      apply (clarsimp)
      apply (thin_tac "lookup''  (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Miss")
      apply (drule union_asid_tlb_incon_cases)
      apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pt_walk_not_incon apply force
      apply (erule disjE, clarsimp simp: )
       apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
       apply (clarsimp simp: non_global_to_global [symmetric])
       apply (case_tac "fst(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
        apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
       apply (subgoal_tac "\<not>is_fault (pt_walk a (MEM s) (TTBR0 s) v)")
        apply (subgoal_tac "xa = the (pt_walk a (MEM s) (TTBR0 s) v)")
         apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
         apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
         apply (metis pt_walk_new_no_fault_pt_walk' option.inject)
        apply (frule_tac a' = a in non_global_lookup_hit_asid, simp)
       apply (rule non_global_hit_no_fault, simp)
      apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pt_walk_not_incon apply force
      apply (erule disjE, clarsimp simp: )
       apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
       apply (clarsimp simp: non_global_to_global [symmetric])
       apply (clarsimp simp: lookup_from'_def snap_conv'_def split:  pt_walk_typ.splits if_split_asm option.splits)
      apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pt_walk_not_incon apply force
      apply (clarsimp simp: )
      apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
      apply (clarsimp simp: non_global_to_global [symmetric])
      apply (clarsimp simp: lookup_from'_def snap_conv'_def split:  pt_walk_typ.splits if_split_asm option.splits)
     apply (rule tlb_nion_global_non_global)
    apply (clarsimp)
    apply (rename_tac v)
    apply (subgoal_tac "snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =  (non_global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>
                          (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
     apply (simp only:)
     apply (thin_tac "snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =  (non_global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>
                          (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
     apply (subgoal_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)))  a v = lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union>  global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v ")
      prefer 2
      apply (rule saturated_global_subset_lookup_pdc_un_eq[symmetric], simp)
     apply (drule_tac t = "non_global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})" in union_asid_pdc_incon_cases)
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))
                       a v =  Incon")
      apply (subgoal_tac "v \<in> iset (set_tlb t)")
       apply (subgoal_tac "v \<in> global_set (set_tlb t)")
        apply blast
       apply (clarsimp simp: global_entries_pdc_def lookup_def asid_of_pdc_def tagged_pdc_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
       apply blast
      apply (drule_tac a' = "ASID s" in lookup_global_incon_incon_pdc')
      apply blast
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Hit xa")
      apply (case_tac "v \<in> global_set (set_tlb t)")
       apply (case_tac "v \<in> iset (set_tlb t)")
        apply blast
       apply clarsimp
       apply (subgoal_tac "lookup_pdc  (snd(sat_tlb s)) (ASID s) v = Hit xa \<or>
                           lookup_pdc  (snd(sat_tlb s)) (ASID s) v = Incon")
        apply (erule_tac P = "lookup_pdc  (snd(sat_tlb s)) (ASID s) v = Hit xa" in disjE)
         apply (case_tac "is_fault (pdc_walk (ASID s) (MEM s) (TTBR0 s) v)")
          apply (clarsimp simp: incoherrent_vaddrs_def)
          apply force
         apply (drule  lookup_asid_pdc_hit_union_cases')
         apply (erule disjE, clarsimp)
          apply (subgoal_tac "asid_of_pdc (the (pdc_walk a (MEM s) (TTBR0 s) v)) = None")
           apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
           apply (clarsimp simp: non_global_to_global_pdc [symmetric])
           apply (case_tac "snd(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
            apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
           apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
             apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
             apply (metis option.sel option.simps(3) pt_walk_new_no_fault_pdc_walk pt_walk_new_par_fault_pdc_walk)
            apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
            apply (metis option.sel option.simps(3) pt_walk_new_no_fault_pdc_walk )
           apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
           apply (metis lookup_non_global_hit_asid_of_not_none_pdc option.sel pt_walk_new_no_fault_pdc_walk)
          apply (rule_tac v = v and a = a and t = "(the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})" in lookup_global_hit_asid_of_none_pdc)
          apply (subgoal_tac "\<not> is_fault (pdc_walk a (MEM s) (TTBR0 s) v)")
           apply (rule lookup_pdc_non_global_miss_non_fault, simp, simp)
  using no_fault_pdc_walk_unequal_asid' apply blast
         apply (erule disjE, clarsimp)
          apply (subgoal_tac "xa \<noteq> the (pdc_walk (ASID t) (MEM s) (TTBR0 s) v)")
           apply (drule_tac b = v and x = xa in saturatd_lookup_pdc_hit_no_fault; simp?)
          apply (subgoal_tac "asid_of_pdc xa = None")
           apply (subgoal_tac "asid_of_pdc (the (pdc_walk (ASID t) (MEM s) (TTBR0 s) v)) \<noteq> None")
            apply force
           apply (subgoal_tac "lookup_pdc (non_global_entries_pdc (the ` {e \<in> range (pdc_walk (ASID t) (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID t) v = Hit
                              (the (pdc_walk (ASID t) (MEM s) (TTBR0 s) v))")
            apply (rule lookup_non_global_hit_asid_of_not_none_pdc, simp)
           apply (rule_tac a = a in non_global_lookup_pdc_hit_asid, simp)
          apply (rule lookup_global_hit_asid_of_none_pdc, simp)
         apply (clarsimp)
         apply (subgoal_tac "xa \<noteq> the (pdc_walk (ASID t) (MEM s) (TTBR0 s) v)")
          apply (drule_tac b = v and x = xa in saturatd_lookup_pdc_hit_no_fault; simp?)
         apply (subgoal_tac "asid_of_pdc xa = None")
          apply (subgoal_tac "asid_of_pdc (the (pdc_walk (ASID t) (MEM s) (TTBR0 s) v)) \<noteq> None")
           apply force
          apply (subgoal_tac "lookup_pdc (non_global_entries_pdc (the ` {e \<in> range (pdc_walk (ASID t) (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID t) v = Hit
                              (the (pdc_walk (ASID t) (MEM s) (TTBR0 s) v))")
           apply (rule lookup_non_global_hit_asid_of_not_none_pdc, simp)
          apply (rule_tac a = a in non_global_lookup_pdc_hit_asid, simp)
         apply (rule lookup_global_hit_asid_of_none_pdc, simp)
        apply blast
       apply (metis lookup_global_same_for_asids_pdc lookup_pdc_global_hit_order)
      apply (subgoal_tac "xa \<in> global_entries_pdc (snd(sat_tlb s))")
       apply (subgoal_tac "v \<in> range_of xa")
        apply (clarsimp simp: global_range_def)
        apply blast
       apply (simp add: lookup_asid_pdc_hit_entry_range)
  using lookup_in_asid_pdc apply auto[1]
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))
                       a v =  Incon")
      apply (subgoal_tac "v \<in> iset (set_tlb t)")
       apply (subgoal_tac "v \<in> global_set (set_tlb t)")
        apply blast
       apply (clarsimp simp: global_entries_pdc_def lookup_def asid_of_pdc_def tagged_pdc_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
       apply blast
      apply (drule_tac a' = "ASID s" in lookup_global_incon_incon_pdc')
      apply blast
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union>  global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))a v = Hit x")
      apply (drule union_asid_pdc_incon_cases)
      apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pdc_walk_not_incon apply force
      apply (erule disjE, clarsimp simp: )
       apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
       apply (clarsimp simp: non_global_to_global_pdc [symmetric])
       apply (case_tac "snd(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
        apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
       apply (subgoal_tac "\<not>is_fault (pdc_walk a (MEM s) (TTBR0 s) v)")
        apply (subgoal_tac "xb = the (pdc_walk a (MEM s) (TTBR0 s) v)")
         apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
           apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
           apply (metis option.inject pt_walk_new_no_fault_pdc_walk pt_walk_new_par_fault_pdc_walk)
          apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
          apply (metis option.inject pt_walk_new_no_fault_pdc_walk pt_walk_new_par_fault_pdc_walk)
         apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
         apply (metis option.inject pt_walk_new_no_fault_pdc_walk pt_walk_new_par_fault_pdc_walk)
        apply (frule_tac a' = a in non_global_lookup_pdc_hit_asid, simp)
       apply (rule non_global_hit_no_fault_pdc, simp)
      apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pdc_walk_not_incon apply force
      apply (erule disjE, clarsimp simp: )
       apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
       apply (clarsimp simp: non_global_to_global_pdc [symmetric])
       apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
      apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pdc_walk_not_incon apply force
      apply (clarsimp simp: )
      apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
      apply (clarsimp simp: non_global_to_global_pdc [symmetric])
      apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))
                       a v =  Incon")
      apply (subgoal_tac "v \<in> iset (set_tlb t)")
       apply (subgoal_tac "v \<in> global_set (set_tlb t)")
        apply blast
       apply (clarsimp simp: global_entries_pdc_def lookup_def asid_of_pdc_def tagged_pdc_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
       apply blast
      apply (drule_tac a' = "ASID s" in lookup_global_incon_incon_pdc')
      apply blast
     apply (clarsimp)
     apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Miss")
     apply (drule union_asid_pdc_incon_cases)
     apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pdc_walk_not_incon apply force
     apply (erule disjE, clarsimp simp: )
      apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
      apply (clarsimp simp: non_global_to_global_pdc [symmetric])
      apply (case_tac "snd(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
       apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
      apply (subgoal_tac "\<not>is_fault (pdc_walk a (MEM s) (TTBR0 s) v)")
       apply (subgoal_tac "xa = the (pdc_walk a (MEM s) (TTBR0 s) v)")
        apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
          apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
          apply (metis (no_types, hide_lams) non_fault_pt_walk_pair_disjI option.inject
      option.sel pt_walk_full_no_pdc_fault pt_walk_new_par_fault_pdc_walk pt_walk_typ.inject(2) pt_walk_typ.simps(8))
         apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
         apply (metis option.inject pt_walk_new_no_fault_pdc_walk)
        apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
        apply (metis option.inject pt_walk_new_no_fault_pdc_walk)
       apply (frule_tac a' = a in non_global_lookup_pdc_hit_asid, simp)
      apply (rule non_global_hit_no_fault_pdc, simp)
     apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pdc_walk_not_incon apply force
     apply (erule disjE, clarsimp simp: )
      apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
      apply (clarsimp simp: non_global_to_global_pdc [symmetric])
      apply (clarsimp simp: lookup_from'_def snap_conv'_def split:  pt_walk_typ.splits if_split_asm option.splits)
     apply (erule disjE, clarsimp simp: )
  using non_global_lookup_range_pdc_walk_not_incon apply force
     apply (clarsimp simp: )
     apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
     apply (clarsimp simp: non_global_to_global_pdc [symmetric])
     apply (clarsimp simp: lookup_from'_def snap_conv'_def split:  pt_walk_typ.splits if_split_asm option.splits)
    apply (rule pdc_non_global_non_global)
   apply (clarsimp simp: incoherrent_vaddrs_def)
   apply (rule conjI)
    apply clarsimp
    apply (rename_tac v x)
    apply (subgoal_tac "fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =
                                             (non_global_entries (fst(sat_tlb s)) \<union> non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>  (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
     apply (simp only:)
     apply (thin_tac "fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =
                                             (non_global_entries (fst(sat_tlb s)) \<union> non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>  (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
     apply (subgoal_tac "lookup''   (global_entries (fst(sat_tlb s)))  a v = lookup'' (global_entries (fst(sat_tlb s)) \<union>  global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v ")
      prefer 2
      apply (rule saturated_global_subset_lookup_tlb_un_eq[symmetric], simp)
     apply (drule_tac t = "non_global_entries (fst(sat_tlb s)) \<union> non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})" in  lookup_asid_tlb_hit_union_cases')
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup''(global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Miss")
      apply (subgoal_tac "lookup'' (non_global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Miss")
       apply (drule  lookup_asid_tlb_hit_union_cases')
       apply (erule disjE, clarsimp)
        apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
        apply (clarsimp simp: non_global_to_global [symmetric])
        apply (case_tac "fst(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
         apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
        apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
        apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
        apply (metis option.simps(3) pt_walk_new_no_fault_pt_walk')
       apply (erule disjE, clarsimp)
       apply (clarsimp)
      apply (rule is_fault_non_global_entries_miss, simp)
     apply (erule disjE, clarsimp)
      apply (thin_tac "lookup''  (global_entries (fst(sat_tlb s)) \<union> global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v =  Hit x")
      apply (subgoal_tac "v \<in> global_set (set_tlb t)")
       apply (case_tac "v \<in> iset (set_tlb t)")
        apply blast
       apply (subgoal_tac " lookup''  (fst(sat_tlb s)) (ASID t) v = Hit x \<or>
                       lookup''  (fst(sat_tlb s)) (ASID t) v = Incon")
        prefer 2
        apply (metis (no_types, hide_lams)  lookup_global_hit_order lookup_global_same_for_asids )
       apply (erule disjE)
        apply (clarsimp simp: )
  using no_fault_pt_walk_unequal_asid' apply fastforce
       apply (clarsimp simp: inconsistent_vaddrs_def) apply force
      apply (clarsimp simp: global_entries_def lookup_def tagged_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
      apply blast
     apply (clarsimp)
     apply (subgoal_tac "v \<in> global_set (set_tlb t)")
      apply (case_tac "v \<in> iset (set_tlb t)")
       apply blast
      apply (subgoal_tac " lookup''  (fst(sat_tlb s)) (ASID t) v = Hit x \<or>
                       lookup''  (fst(sat_tlb s)) (ASID t) v = Incon")
       prefer 2
       apply (metis (no_types, hide_lams)  lookup_global_hit_order lookup_global_same_for_asids )
      apply (erule disjE)
       apply (clarsimp simp: )
  using no_fault_pt_walk_unequal_asid' apply fastforce
      apply (clarsimp simp: inconsistent_vaddrs_def) apply force
     apply (clarsimp simp: global_entries_def lookup_def tagged_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
     apply blast
    apply (rule tlb_nion_global_non_global)
   apply clarsimp
   apply (rename_tac v x)
   apply (subgoal_tac "snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =
                                             (non_global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>  (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
    apply (simp only:)
    apply (thin_tac "snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} =
                                             (non_global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) \<union>  (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}))")
    apply (subgoal_tac "lookup_pdc   (global_entries_pdc (snd(sat_tlb s)))  a v = lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union>  global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v ")
     prefer 2
     apply (rule saturated_global_subset_lookup_pdc_un_eq[symmetric], simp)
    apply (drule_tac t = "non_global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})" in  lookup_asid_pdc_hit_union_cases')
    apply (erule disjE, clarsimp)
     apply (thin_tac "lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Miss")
     apply (subgoal_tac "lookup_pdc (non_global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v = Miss")
      apply (drule  lookup_asid_pdc_hit_union_cases')
      apply (erule disjE, clarsimp)
       apply (drule_tac x = a in spec, simp, drule_tac x = v in spec)
       apply (clarsimp simp: non_global_to_global_pdc [symmetric])
       apply (case_tac "snd(lookup_from' (snapshot (set_tlb t)) a v)"; clarsimp?)
        apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
       apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
         apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
         apply (metis is_fault_def pt_walk_full_no_pdc_fault pt_walk_partial_no_pdc_fault)
        apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
        apply (metis is_fault_def pt_walk_full_no_pdc_fault)
       apply (clarsimp simp: ptable_comp_def is_fault_def entry_leq_def)
       apply (metis is_fault_def pt_walk_full_no_pdc_fault)
      apply (erule disjE, clarsimp)
      apply (clarsimp)
     apply (rule is_fault_non_global_entries_pdc_miss,simp)
    apply (erule disjE, clarsimp)
     apply (thin_tac "lookup_pdc  (global_entries_pdc (snd(sat_tlb s)) \<union> global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) a v =  Hit x")
     apply (subgoal_tac "v \<in> global_set (set_tlb t)")
      apply (case_tac "v \<in> iset (set_tlb t)")
       apply blast
      apply (subgoal_tac " lookup_pdc  (snd(sat_tlb s)) (ASID t) v = Hit x \<or>
                       lookup_pdc  (snd(sat_tlb s)) (ASID t) v = Incon")
       prefer 2
       apply (metis (no_types, hide_lams)  lookup_pdc_global_hit_order lookup_global_same_for_asids_pdc )
      apply (erule disjE)
       apply (clarsimp simp: )
  using no_fault_pdc_walk_unequal_asid' apply fastforce
      apply (clarsimp simp: inconsistent_vaddrs_def) apply force
     apply (clarsimp simp: global_entries_pdc_def lookup_def asid_of_pdc_def tagged_pdc_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
     apply blast
    apply (clarsimp)
    apply (subgoal_tac "v \<in> global_set (set_tlb t)")
     apply (case_tac "v \<in> iset (set_tlb t)")
      apply blast
     apply (subgoal_tac " lookup_pdc  (snd(sat_tlb s)) (ASID t) v = Hit x \<or>
                       lookup_pdc  (snd(sat_tlb s)) (ASID t) v = Incon")
      prefer 2
      apply (metis (no_types, hide_lams)  lookup_pdc_global_hit_order lookup_global_same_for_asids_pdc )
     apply (erule disjE)
      apply (clarsimp simp: )
  using no_fault_pdc_walk_unequal_asid' apply fastforce
     apply (clarsimp simp: inconsistent_vaddrs_def) apply force
    apply (clarsimp simp: global_entries_pdc_def lookup_def asid_of_pdc_def tagged_pdc_entry_set_def entry_set_def global_range_def split: if_split_asm option.splits)
    apply blast
   apply (rule pdc_non_global_non_global)
  apply (rule conjI)
   apply (clarsimp simp: global_range_def)
   apply (rule conjI)

    apply (subgoal_tac "global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) =
                         global_entries (fst(sat_tlb s))")
     apply (simp only:)
    apply (subgoal_tac "global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) \<subseteq>
          global_entries (fst(sat_tlb s))" )
     apply (clarsimp simp: global_entries_union)
     apply blast
    apply (subgoal_tac "global_entries (the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) =
                       global_entries (the ` {e \<in> range (pt_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e})")
     apply (simp only:)
     apply (clarsimp simp: saturated_def global_entries_def) apply force
    apply (rule global_entries_ptable_same)
   apply (subgoal_tac "global_entries_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) =
                         global_entries_pdc (snd(sat_tlb s))")
    apply (simp only:)
   apply (subgoal_tac "global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) \<subseteq>
          global_entries_pdc (snd(sat_tlb s))" )
    apply (clarsimp simp: global_entries_union_pdc)
    apply blast

   apply (subgoal_tac "global_entries_pdc (the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e}) =
                       global_entries_pdc (the ` {e \<in> range (pdc_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e})")
    apply (simp only:)
    apply (clarsimp simp: saturated_def global_entries_pdc_def) apply force
   apply (rule global_entries_pdc_ptable_same)
  apply (clarsimp simp: )
  apply (rule conjI)
   apply (subgoal_tac "(fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} - global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) =
                                                                                non_global_entries (fst(sat_tlb s)\<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})")
    apply (simp only:)
    apply (thin_tac "(fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} - global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) =
                                                                                non_global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})")
    apply (case_tac "aa = ASID t")
     apply (thin_tac " \<forall>a. a \<noteq> ASID s \<longrightarrow>
            (\<forall>v. lookup'' (fst (sat_tlb s) - global_entries (fst (sat_tlb s))) a v \<le> fst (lookup_from' (snapshot (set_tlb t)) a v) \<and>
                 lookup_pdc (snd (sat_tlb s) - global_entries_pdc (snd (sat_tlb s))) a v \<le> snd (lookup_from' (snapshot (set_tlb t)) a v))")
     apply (clarsimp)
     apply (subgoal_tac "lookup'' (non_global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID t) v =
                                                              lookup'' (non_global_entries (fst(sat_tlb s))) (ASID t) v")
      apply (simp only:)
      apply (thin_tac "lookup'' (non_global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID s) v =
                                                              lookup'' (non_global_entries (fst(sat_tlb s))) (ASID s) v")
      apply (case_tac "fst(lookup_from' (snp_upd_cur' (snapshot (set_tlb t)) (iset (set_tlb t)) (MEM s) (TTBR0 s) (ASID t)) (ASID t) v)"; clarsimp)
       apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
          apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
          apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)")
           apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
           apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
           apply (metis lookup_asid_tlb_miss_union lookup_tlb_eq_union_global_non_global lookup_type.exhaust option.simps(3) pt_walk_new_fault_pt_walk_fault')
          apply blast
         apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
         apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)")
          apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
          apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
          apply (metis lookup_asid_tlb_miss_union not_miss_incon_hit_asid_tlb option.discI pt_walk_new_par_fault_pt_walk_fault' tlb_global_non_global_union)
         apply blast
        apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
        apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)")
         apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
         apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
         apply (metis lookup_asid_tlb_miss_union not_miss_incon_hit_asid_tlb option.discI pt_walk_new_par_fault_pt_walk_fault' tlb_global_non_global_union)
        apply blast
       apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
       apply (subgoal_tac "x31 = the (pt_walk (ASID t) (MEM s) (TTBR0 s) v)")
        prefer 2
        apply (simp add: pt_walk_new_no_fault_pt_walk')
       apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)") prefer 2 apply blast
       apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
       apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
       apply (case_tac "lookup'' (fst(sat_tlb s)) (ASID s) v"; clarsimp)
        apply (metis lookup_asid_tlb_miss_union tlb_global_non_global_union)
       apply (subgoal_tac "lookup'' (fst(sat_tlb s)) (ASID s) v = lookup'' (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e}) (ASID t) v")
        prefer 2
        apply (clarsimp simp: saturated_def)
        apply (simp add: sup.absorb1)
       apply (simp only:)
       apply (drule lookup_asid_tlb_hit_union_cases')
       apply (thin_tac "(\<forall>x. lookup_pdc (snd (sat_tlb s)) (ASID s) v \<noteq> Hit x) \<or> (\<exists>y. pdc_walk (ASID s) (MEM s) (TTBR0 s) v = Some y)")
       apply (erule disjE, clarsimp)
        apply (subgoal_tac "is_fault (pt_walk (ASID s) (MEM s) (TTBR0 s) v)")
         apply (clarsimp simp: is_fault_def)
        apply (rule asid_tlb_lookup_miss_is_fault, simp)
       apply (erule disjE, clarsimp)
       apply (clarsimp)
       apply (subgoal_tac "x3 = y") apply clarsimp
        apply (subgoal_tac "lookup'' (fst(sat_tlb s)) (ASID s) v = lookup'' (global_entries (fst(sat_tlb s)) \<union> non_global_entries (fst(sat_tlb s))) (ASID s) v ")
         apply (simp only:)
         apply (thin_tac "  lookup'' (the ` {e \<in> range (pt_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e}) (ASID s) v = Hit y ")
         apply (drule lookup_asid_tlb_hit_union_cases')
         apply (erule disjE, clarsimp)
         apply (erule disjE, clarsimp)
          apply (drule lookup_non_global_hit_asid_of_not_none, simp)
         apply (clarsimp)
         apply (drule lookup_non_global_hit_asid_of_not_none, simp)
        apply (clarsimp) apply (insert tlb_global_non_global_union [of "fst(sat_tlb s)"])
        apply (simp add: Un_commute)
       apply (frule asid_tlb_lookup_range_fault_pt_walk)
       apply (drule_tac x = v in bspec)
  using lookup_asid_tlb_hit_entry_range apply force
       apply simp
      apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
      apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
      apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)") prefer 2 apply blast
      apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
      apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
      apply (case_tac "lookup'' (fst(sat_tlb s)) (ASID t) v"; clarsimp)
       apply (simp only: non_global_to_global)
       apply (subgoal_tac "lookup'' (fst(sat_tlb s) - global_entries (fst(sat_tlb s))) (ASID t) v = Miss") apply simp
       apply (rule lookup_miss_minus_miss, simp)
      apply (subgoal_tac "x3a = x3", simp)
       apply (simp only: non_global_to_global)
       apply (subgoal_tac "lookup'' (fst(sat_tlb s) - global_entries (fst(sat_tlb s))) (ASID t) v = Miss \<or>
                 lookup'' (fst(sat_tlb s) - global_entries (fst(sat_tlb s))) (ASID t) v = Hit x3")
        apply force
       apply (rule lookup_miss_minus_miss_hit, simp)
      apply (frule_tac b = v and x = x3a in  saturatd_lookup_hit_no_fault, simp,
      simp add: is_fault_def, simp)
  using pt_walk_new_no_fault_pt_walk' apply force
     apply (rule lookup_non_global_union_asid_unequal, simp)
    apply (drule_tac x = aa in spec, simp, drule_tac x = v in spec)
    apply (subgoal_tac "lookup'' (non_global_entries (fst(sat_tlb s) \<union> the ` {e \<in> range (pt_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) aa v =
                                         lookup'' (non_global_entries (fst(sat_tlb s))) aa v")
     apply (simp only: non_global_to_global)
     apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
     apply (clarsimp simp: lookup_from'_def snap_conv'_def split: if_split_asm option.splits)
    apply (rule lookup_non_global_union_asid_unequal', simp, simp, simp)
  using non_global_to_global apply auto [1]
  apply (subgoal_tac "(snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} - global_entries_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) =
                                                                                non_global_entries_pdc (snd(sat_tlb s)\<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})")
   apply (simp only:)
   apply (thin_tac "(snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e} - global_entries_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) =
                                                                                non_global_entries_pdc (snd(sat_tlb s)\<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})")
   apply (case_tac "aa = ASID t")
    apply (thin_tac " \<forall>a. a \<noteq> ASID s \<longrightarrow>
            (\<forall>v. lookup'' (fst (sat_tlb s) - global_entries (fst (sat_tlb s))) a v \<le> fst (lookup_from' (snapshot (set_tlb t)) a v) \<and>
                 lookup_pdc (snd (sat_tlb s) - global_entries_pdc (snd (sat_tlb s))) a v \<le> snd (lookup_from' (snapshot (set_tlb t)) a v))")
    apply (clarsimp)
    apply (subgoal_tac "lookup_pdc (non_global_entries_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID s) v =
                                                              lookup_pdc (non_global_entries_pdc (snd(sat_tlb s))) (ASID s) v")
     apply (simp only:)
     apply (thin_tac  "lookup_pdc (non_global_entries_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) (ASID s) v =
                                                              lookup_pdc (non_global_entries_pdc (snd(sat_tlb s))) (ASID s) v")
     apply (case_tac "snd(lookup_from' (snp_upd_cur' (snapshot (set_tlb t)) (iset (set_tlb t)) (MEM s) (TTBR0 s) (ASID t)) (ASID t) v)"; clarsimp)
      apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
        apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
        apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)")
         apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
         apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
         apply (metis (full_types) global_entries_pdc_def leq_Miss less_eq_lookup_type lookup_asid_pdc_miss_union lookup_eq_union_global_non_global_pdc lookup_type.exhaust lookup_type.simps(3) non_global_entries_pdc_def
      not_Some_eq pt_walk_new_fault_pdc_walk_fault' pt_walk_pair_def typ_sat_prim_parameter typ_sat_tlb_def)
        apply blast
       apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
       apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)")
        apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
        apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)

  subgoal
  proof -
    fix v :: vaddr and x2 :: pdc_entry
    assume a1: "saturated (typ_sat_tlb s)"
    assume a2: "pt_walk_pair (ASID s) (MEM s) (TTBR0 s) v = Partial_Walk x2"
    assume a3: "asid_of_pdc x2 = None"
    assume a4: "lookup_pdc (snd (sat_tlb s)) (ASID s) v \<noteq> Incon"
    have "the (Some x2) = x2"
      by simp
    moreover
    { assume "lookup_pdc (snd (sat_tlb s)) (ASID s) v = Hit x2"
      then have "\<exists>P. lookup_pdc (P \<union> non_global_entries_pdc (snd (sat_tlb s))) (ASID s) v = Hit x2"
        by (metis (no_types) lookup_eq_union_global_non_global_pdc)
      then have "lookup_pdc (non_global_entries_pdc (snd (sat_tlb s))) (ASID s) v = Miss"
        using a3 lookup_asid_pdc_hit_union_cases' lookup_non_global_hit_asid_of_not_none_pdc by blast }
    ultimately show "lookup_pdc (non_global_entries_pdc (snd (sat_tlb s))) (ASID s) v = Miss"
      using a4 a2 a1 by (metis (no_types) lookup_asid_pdc_miss_union pdc_global_non_global_union pt_walk_new_par_fault_pdc_walk pt_walk_partial_no_pdc_fault saturate_no_icon_miss)
  qed
       apply blast
      apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
      apply (subgoal_tac "x32 = the (pdc_walk (ASID s) (MEM s) (TTBR0 s) v)")
       prefer 2
       apply (simp add: pt_walk_new_no_fault_pdc_walk)
      apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)") prefer 2 apply blast
      apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
      apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
      apply (case_tac "lookup_pdc (snd(sat_tlb s)) (ASID s) v"; clarsimp)
  using pt_walk_full_no_pdc_fault sat_miss_pdc_fault apply fastforce
      apply (subgoal_tac "lookup_pdc (snd(sat_tlb s)) (ASID s) v = lookup_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e}) (ASID t) v")
       prefer 2
       apply (clarsimp simp: saturated_def)
       apply (simp add: sup.absorb1)
      apply (simp only:)
      apply (drule lookup_asid_pdc_hit_union_cases')
      apply (thin_tac "(\<forall>x. lookup'' (fst (sat_tlb s)) (ASID s) v \<noteq> Hit x) \<or> (\<exists>y. pt_walk (ASID s) (MEM s) (TTBR0 s) v = Some y)")
      apply (erule disjE, clarsimp)
       apply (subgoal_tac "is_fault (pdc_walk (ASID s) (MEM s) (TTBR0 s) v)")
        apply (clarsimp simp: is_fault_def)
       apply (rule lookup_pdc_miss_is_fault, simp)
      apply (erule disjE, clarsimp)
      apply (clarsimp)
      apply (subgoal_tac "x3 = y") apply clarsimp
       apply (subgoal_tac "lookup_pdc (snd(sat_tlb s)) (ASID s) v = lookup_pdc (global_entries_pdc (snd(sat_tlb s)) \<union> non_global_entries_pdc (snd(sat_tlb s))) (ASID s) v ")
        apply (simp only:)
        apply (thin_tac "  lookup_pdc (the ` {e \<in> range (pdc_walk (ASID s) (MEM s) (TTBR0 s)). \<not> is_fault e}) (ASID s) v = Hit y ")
        apply (drule lookup_asid_pdc_hit_union_cases')
        apply (erule disjE, clarsimp)
        apply (erule disjE, clarsimp)
         apply (drule lookup_non_global_hit_asid_of_not_none_pdc, simp)
        apply (clarsimp)
        apply (drule lookup_non_global_hit_asid_of_not_none_pdc, simp)
       apply (clarsimp) apply (insert pdc_global_non_global_union [of "snd(sat_tlb s)"])
       apply (simp add: Un_commute)
      apply (frule lookup_pdc_range_fault_pt_walk)
      apply (drule_tac x = v in bspec)
  using lookup_asid_pdc_hit_entry_range apply blast
      apply simp
     apply (clarsimp simp: lookup_from'_def snap_conv'_def split: pt_walk_typ.splits if_split_asm option.splits)
       apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
       apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)") prefer 2 apply blast
       apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
       apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
       apply (case_tac "lookup_pdc (snd(sat_tlb s)) (ASID t) v"; clarsimp)
        apply (simp only: non_global_to_global_pdc)
        apply (subgoal_tac "lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Miss") apply simp
        apply (rule lookup_miss_minus_miss_pdc, simp)
       apply (subgoal_tac "x3a = x3", simp)
        apply (simp only: non_global_to_global_pdc)
        apply (subgoal_tac "lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Miss \<or>
                 lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Hit x3")
         apply force
        apply (rule lookup_miss_minus_miss_hit_pdc, simp)
       apply (frule_tac b = v and x = x3a in  saturatd_lookup_pdc_hit_no_fault, simp,
      simp add: is_fault_def, simp)
       apply (simp add: pt_walk_new_par_fault_pdc_walk)
      apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
      apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)") prefer 2 apply blast
      apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
      apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
      apply (case_tac "lookup_pdc (snd(sat_tlb s)) (ASID t) v"; clarsimp)
       apply (simp only: non_global_to_global_pdc)
       apply (subgoal_tac "lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Miss") apply simp
       apply (rule lookup_miss_minus_miss_pdc, simp)
      apply (subgoal_tac "x3a = x3", simp)
       apply (simp only: non_global_to_global_pdc)
       apply (subgoal_tac "lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Miss \<or>
                 lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Hit x3")
        apply force
       apply (rule lookup_miss_minus_miss_hit_pdc, simp)
      apply (frule_tac b = v and x = x3a in  saturatd_lookup_pdc_hit_no_fault, simp,
      simp add: is_fault_def, simp)
  using pt_walk_new_no_fault_pdc_walk apply force
     apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
     apply (subgoal_tac "v \<notin> incon_addrs (typ_sat_tlb s)") prefer 2 apply blast
     apply (thin_tac "incon_addrs (typ_sat_tlb s) \<subseteq> iset (set_tlb t)")
     apply (clarsimp simp: incon_addrs_def inconsistent_vaddrs_def incoherrent_vaddrs_def is_fault_def)
     apply (case_tac "lookup_pdc (snd(sat_tlb s)) (ASID t) v"; clarsimp)
      apply (simp only: non_global_to_global_pdc)
      apply (subgoal_tac "lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Miss") apply simp
      apply (rule lookup_miss_minus_miss_pdc, simp)
     apply (subgoal_tac "x3a = x3", simp)
      apply (simp only: non_global_to_global_pdc)
      apply (subgoal_tac "lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Miss \<or>
                 lookup_pdc (snd(sat_tlb s) - global_entries_pdc (snd(sat_tlb s))) (ASID t) v = Hit x3")
       apply force
      apply (rule lookup_miss_minus_miss_hit_pdc, simp)
     apply (frule_tac b = v and x = x3a in  saturatd_lookup_pdc_hit_no_fault, simp,
      simp add: is_fault_def, simp)
  using pt_walk_new_no_fault_pdc_walk apply force
    apply (rule lookup_non_global_union_asid_unequal_pdc, simp)
   apply (drule_tac x = aa in spec, simp, drule_tac x = v in spec)
   apply (subgoal_tac "lookup_pdc (non_global_entries_pdc (snd(sat_tlb s) \<union> the ` {e \<in> range (pdc_walk a (MEM s) (TTBR0 s)). \<not> is_fault e})) aa v =
                                         lookup_pdc (non_global_entries_pdc (snd(sat_tlb s))) aa v")
    apply (simp only: non_global_to_global_pdc)
    apply (clarsimp simp: snp_upd_cur'_def snp_upd_cur_def)
    apply (clarsimp simp: lookup_from'_def snap_conv'_def split: if_split_asm option.splits)
   apply (rule lookup_non_global_union_asid_unequal_pdc', simp, simp, simp)
  using non_global_to_global_pdc by auto [1]

end


theory Timeout
imports Semantics PositiveAccounts QuiescentResult AssetsPreservation
begin

fun isClosedAndEmpty :: "TransactionOutput \<Rightarrow> bool" where
"isClosedAndEmpty (TransactionOutput txOut) = (txOutContract txOut = Close
                                               \<and> accounts (txOutState txOut) = [])" |
"isClosedAndEmpty _ = False"

lemma max_of_ge : "ia \<le> i \<Longrightarrow> max (i::int) ia = i"
  by linarith

lemma reduceStepClose_is_Close : "reduceContractStep env sta Close = Reduced re wa nsta ncon \<Longrightarrow> ncon = Close"
  apply simp
  apply (cases "refundOne (accounts sta)")
  apply simp
  subgoal for a
    apply (cases "a")
    subgoal for aa b
      apply (cases "aa")
      by simp
    done
  done

lemma reductionLoopClose_is_Close : "reductionLoop reduced env sta Close x y = ContractQuiescent newReduced re wa nsta ncon \<Longrightarrow> ncon = Close"
  apply (induction reduced env sta Close x y rule:reductionLoop.induct)
  subgoal for reduced env state warnings payments
    apply (simp only:reductionLoop.simps)
    apply (cases "reduceContractStep env state Close")
    subgoal for x11 x12 x13 x14
      apply (simp del:reductionLoop.simps reduceContractStep.simps add:reduceStepClose_is_Close)
      using reduceStepClose_is_Close by fastforce
    apply (simp del:reduceContractStep.simps)
    apply (simp del:reduceContractStep.simps)
    done
  done

lemma reduceClose_is_Close : "reduceContractUntilQuiescent env sta Close = ContractQuiescent reduced re wa nsta ncon \<Longrightarrow> ncon = Close"
  apply (simp del:reductionLoop.simps)
  using reductionLoopClose_is_Close by blast

lemma timedOutReduce_only_quiescent_in_close_When :
  "minTime sta \<le> iniTime \<Longrightarrow>
   maxTimeContract (When x41 x42 x43) \<le> iniTime \<Longrightarrow>
   iniTime \<le> endTime \<Longrightarrow>
   reduceContractStep \<lparr>timeInterval = (iniTime, endTime)\<rparr> (sta\<lparr>minTime := iniTime\<rparr>) (When x41 x42 x43) \<noteq> NotReduced"
  apply (induction x41)
  by simp_all

lemma maxTimeWhen : "maxTimeContract (When x41 x42 x43) \<le> iniTime \<Longrightarrow> x42 \<le> iniTime"
  apply (induction x41 arbitrary:x42 x43 iniTime)
  by auto

lemma maxTimeNotAmbiguous_reduceStep :
   "maxTimeContract cont \<le> iniTime \<Longrightarrow>
    iniTime \<le> endTime \<Longrightarrow>
    reduceContractStep \<lparr>timeInterval = (iniTime, endTime)\<rparr> state cont \<noteq> AmbiguousTimeIntervalReductionError"
  apply (cases cont)
  apply simp
  apply (auto split:option.split bool.split)
  subgoal for x21 x22 x23 x24 x25
    apply (cases "let moneyToPay = evalValue \<lparr>timeInterval = (iniTime, endTime)\<rparr> state x24 in moneyToPay \<le> 0")
    apply simp
    apply simp
    apply (cases "let moneyToPay = evalValue \<lparr>timeInterval = (iniTime, endTime)\<rparr> state x24;
                      balance = case lookup (x21, x23) (accounts state) of None \<Rightarrow> 0 | Some x \<Rightarrow> x; paidMoney = min balance moneyToPay
                  in giveMoney x21 x22 x23 paidMoney (if balance \<le> moneyToPay then MList.delete (x21, x23) (accounts state)
                                                      else MList.insert (x21, x23) (balance - paidMoney) (accounts state))")
    by (meson ReduceStepResult.distinct(3))
  using maxTimeWhen apply blast
  by (meson ReduceStepResult.distinct(3))

lemma maxTimeOnlyDecreases_reduceStepWhen :
  "reduceContractStep inte state (When x41 x42 x43) = Reduced wa ef nstate ncont \<Longrightarrow>
   maxTimeContract ncont \<le> maxTimeContract (When x41 x42 x43)"
  apply (induction x41 arbitrary: inte state x42 x43 wa ef nstate ncont)
  apply (smt ReduceStepResult.distinct(1) ReduceStepResult.distinct(3) ReduceStepResult.inject maxTimeContract.simps(4) prod.case_eq_if reduceContractStep.simps(4))
  by fastforce

lemma maxTimeOnlyDecreases_reduceStep :
  "reduceContractStep inte state cont = Reduced wa ef nstate ncont \<Longrightarrow>
   maxTimeContract ncont \<le> maxTimeContract cont"
  apply (cases cont)
  using reduceStepClose_is_Close apply blast
  apply (simp only:reduceContractStep.simps)
  subgoal for x21 x22 x23 x24 x25
    apply (cases "let moneyToPay = evalValue inte state x24
                  in evalValue inte state x24 \<le> 0")
    apply simp
    apply simp
    apply (cases "let moneyToPay = evalValue inte state x24; balance = case lookup (x21, x23) (accounts state) of None \<Rightarrow> 0 | Some x \<Rightarrow> x;
                      paidMoney = min balance moneyToPay
                  in giveMoney x21 x22 x23 paidMoney
                               (if balance \<le> moneyToPay then MList.delete (x21, x23) (accounts state)
                                else MList.insert (x21, x23) (balance - paidMoney) (accounts state))")
    by (metis ReduceStepResult.inject eq_iff)
    apply auto[1]
  apply (simp add: maxTimeOnlyDecreases_reduceStepWhen)
  apply (metis ReduceStepResult.inject eq_iff maxTimeContract.simps(6) reduceContractStep.simps(5))
  by simp

lemma maxTimeNotAmbiguous_reduceLoop : "maxTimeContract cont \<le> iniTime \<Longrightarrow>
    iniTime \<le> endTime \<Longrightarrow>
    reductionLoop reduced \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta cont x y \<noteq> RRAmbiguousTimeIntervalError"
  apply (induction reduced "\<lparr>timeInterval = (iniTime, endTime)\<rparr>" sta cont x y rule:reductionLoop.induct)
  subgoal premises facts for reduced state contract warnings payments
    apply (cases "reduceContractStep \<lparr>timeInterval = (iniTime, endTime)\<rparr> state contract")
      apply (simp only:reductionLoop.simps ReduceStepResult.case)
      apply (simp only:Let_def)
      using facts(1) facts(2) facts(3) maxTimeOnlyDecreases_reduceStep apply fastforce
      apply auto[1]
      by (simp add: facts(2) facts(3) maxTimeNotAmbiguous_reduceStep)
    done

lemma maxTimeNotAmbiguous : "maxTimeContract cont \<le> iniTime \<Longrightarrow>
       iniTime \<le> endTime \<Longrightarrow>
       reduceContractUntilQuiescent \<lparr>timeInterval = (iniTime, endTime)\<rparr> (sta\<lparr>minTime := iniTime\<rparr>) cont \<noteq> RRAmbiguousTimeIntervalError"
  using maxTimeNotAmbiguous_reduceLoop by auto

lemma timedOutReduce_only_quiescent_in_close :
  "minTime sta \<le> iniTime \<Longrightarrow>
   maxTimeContract c \<le> iniTime \<Longrightarrow>
   iniTime \<le> endTime \<Longrightarrow>
   reduceContractStep \<lparr>timeInterval = (iniTime, endTime)\<rparr> (sta\<lparr>minTime := iniTime\<rparr>) c = NotReduced \<Longrightarrow> c = Close"
  apply (cases c)
  apply blast
  apply (metis reduceContractStep.simps(2) reduceContractStepPayIsQuiescent)
  apply simp
  using timedOutReduce_only_quiescent_in_close_When apply blast
  apply (metis ReduceStepResult.distinct(1) reduceContractStep.simps(5))
  by simp

lemma timedOutReduceStep_does_not_modify_minTime :
  "minTime sta = iniTime \<Longrightarrow>
   reduceContractStep \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta contract =
   Reduced warning effect newState ncontract \<Longrightarrow> minTime newState = iniTime"
  apply (cases contract)
    apply simp
    apply (cases "refundOne (accounts sta)")
      apply simp
      subgoal for a
        apply (cases a)
        subgoal for aa
          apply (cases aa)
          by auto
        done
      subgoal for x21 x22 x23 x24
      apply (cases "let moneyToPay = evalValue \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta x24
                    in moneyToPay \<le> 0")
      apply auto[1]
      apply simp
      apply (cases "giveMoney x21 x22 x23
           (min (case lookup (x21, x23) (accounts sta) of None \<Rightarrow> 0 | Some x \<Rightarrow> x)
             (evalValue \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta x24))
           (if (case lookup (x21, x23) (accounts sta) of None \<Rightarrow> 0 | Some x \<Rightarrow> x)
               \<le> evalValue \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta x24
            then MList.delete (x21, x23) (accounts sta)
            else MList.insert (x21, x23)
                  ((case lookup (x21, x23) (accounts sta) of None \<Rightarrow> 0 | Some x \<Rightarrow> x) -
                   min (case lookup (x21, x23) (accounts sta) of None \<Rightarrow> 0 | Some x \<Rightarrow> x)
                    (evalValue \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta x24))
                  (accounts sta))")
      by (auto simp:Let_def)
      apply auto[1]
    apply (smt ReduceStepResult.distinct(1) ReduceStepResult.distinct(3) ReduceStepResult.inject State.ext_inject State.surjective State.update_convs(4) prod.case_eq_if reduceContractStep.simps(4))
    apply (smt ReduceStepResult.inject State.ext_inject State.surjective State.update_convs(3) State.update_convs(4) reduceContractStep.simps(5))
    by simp

lemma timedOutReduceContractLoop_closes_contract : "minTime sta \<le> iniTime \<Longrightarrow>
    maxTimeContract cont \<le> iniTime \<Longrightarrow>
    iniTime \<le> endTime \<Longrightarrow>
    minTime sta = iniTime \<Longrightarrow>
    reductionLoop reduced \<lparr>timeInterval = (iniTime, endTime)\<rparr> sta cont x y =
    ContractQuiescent newReduced warning effect newState ncontract \<Longrightarrow>
    ncontract = Close"
  apply (induction reduced "\<lparr>timeInterval = (iniTime, endTime)\<rparr>" sta cont x y arbitrary: warning effect newState ncontract rule:reductionLoop.induct)
  subgoal for reduced state contract warnings payments warning effect newState ncontract
    apply (simp only:reductionLoop.simps[of reduced "\<lparr>timeInterval = (iniTime, endTime)\<rparr>" "(sta\<lparr>minTime := iniTime\<rparr>)" contract warnings payments])
    apply (cases "reduceContractStep \<lparr>timeInterval = (iniTime, endTime)\<rparr> state contract")
    subgoal for x11 x12 x13 x14
      apply (simp only:ReduceStepResult.case Let_def)
      subgoal premises facts
        apply (rule facts(1)[of x11 x12 x13 x14 "(if x11 = ReduceNoWarning then warnings else x11 # warnings)"
                                "(case x12 of ReduceNoPayment \<Rightarrow> payments | ReduceWithPayment payment \<Rightarrow> payment # payments)"
                                warning effect newState ncontract])
        apply simp
        apply simp
        apply simp
        apply simp
        using facts(3) facts(7) maxTimeOnlyDecreases_reduceStep apply fastforce
        apply simp
        using facts(5) facts(7) timedOutReduceStep_does_not_modify_minTime apply blast
        by (metis (no_types, lifting) ReduceStepResult.simps(8) facts(6) facts(7) reductionLoop.simps)
      done
    using timedOutReduce_only_quiescent_in_close apply fastforce
    using maxTimeNotAmbiguous_reduceStep by blast
  done

lemma timedOutReduceContractUntilQuiescent_closes_contract :
  "iniTime \<ge> minTime sta
   \<Longrightarrow> iniTime \<ge> maxTimeContract cont
   \<Longrightarrow> endTime \<ge> iniTime
   \<Longrightarrow> reduceContractUntilQuiescent \<lparr>timeInterval = (max iniTime (minTime sta), endTime)\<rparr> (sta\<lparr>minTime := max iniTime (minTime sta)\<rparr>) cont
   = ContractQuiescent reduced warning effect newState ncontract \<Longrightarrow> ncontract = Close"
  apply (simp only:reduceContractUntilQuiescent.simps)
  by (smt State.select_convs(4) State.surjective State.update_convs(4) timedOutReduceContractLoop_closes_contract)

lemma timedOutReduceContractStep_empties_accounts :
  "validAndPositive_state sta \<Longrightarrow>
    minTime sta \<le> iniTime \<Longrightarrow>
    maxTimeContract cont \<le> iniTime \<Longrightarrow>
    iniTime \<le> endTime \<Longrightarrow>
    reduceContractUntilQuiescent \<lparr>timeInterval = (iniTime, endTime)\<rparr> (sta\<lparr>minTime := iniTime\<rparr>) cont
     = ContractQuiescent reduced warning effect newState ncontract \<Longrightarrow> accounts newState = []"
  by (smt State.ext_inject State.surjective State.update_convs(4) allAccountsPositiveState.elims(3) isQuiescent.simps(1) positiveMoneyInAccountOrNoAccountImpliesAllAccountsPositive reduceContractUntilQuiecentIsQuiescent reduceContractUntilQuiescent.simps timedOutReduceContractLoop_closes_contract validAndPositiveImpliesPositive validAndPositiveImpliesValid validAndPositive_state.elims(3) valid_state.simps)

theorem timedOutTransaction_closes_contract :
  "validAndPositive_state sta
   \<Longrightarrow> iniTime \<ge> minTime sta
   \<Longrightarrow> iniTime \<ge> maxTimeContract cont
   \<Longrightarrow> endTime \<ge> iniTime
   \<Longrightarrow> accounts sta \<noteq> [] \<or> cont \<noteq> Close
   \<Longrightarrow> isClosedAndEmpty (computeTransaction \<lparr> interval = (iniTime, endTime)
                                            , inputs = [] \<rparr> sta cont)"
  apply (simp del:validAndPositive_state.simps reduceContractUntilQuiescent.simps add:Let_def)
  apply (cases "reduceContractUntilQuiescent \<lparr>timeInterval = (max iniTime (minTime sta), endTime)\<rparr> (sta\<lparr>minTime := max iniTime (minTime sta)\<rparr>) cont")
  apply (simp only:ReduceResult.case list.case ApplyAllResult.case max_of_ge)
  apply (cases "cont = Close")
  apply (simp del:validAndPositive_state.simps reduceContractUntilQuiescent.simps)
  apply (metis maxTimeContract.simps(1) reduceContractUntilQuiescent.simps reductionLoopClose_is_Close timedOutReduceContractStep_empties_accounts)
  apply (simp del:validAndPositive_state.simps reduceContractUntilQuiescent.simps)
  subgoal for x11 x12 x13 x14 x15
     apply (rule mp[of x11])
     apply (metis max.orderE timedOutReduceContractStep_empties_accounts timedOutReduceContractUntilQuiescent_closes_contract)
    apply (rule mp[of "x15 = Close"])
    apply (metis (no_types, lifting) ReduceResult.inject ReduceStepResult.exhaust ReduceStepResult.simps(8) ReduceStepResult.simps(9) maxTimeNotAmbiguous_reduceStep reduceContractUntilQuiescent.simps reductionLoop.simps reductionLoop_reduce_monotonic)
    by (metis max.orderE timedOutReduceContractUntilQuiescent_closes_contract)
  apply (simp del:validAndPositive_state.simps reduceContractUntilQuiescent.simps)
  using maxTimeNotAmbiguous by auto

corollary timeOutTransaction_does_not_fail :
  assumes "validAndPositive_state sta"
  assumes "emptyTxAfterDeadline = \<lparr> interval = (iniTime, endTime), inputs = [] \<rparr>"
  assumes "iniTime \<ge> minTime sta"
      and "iniTime \<ge> maxTimeContract cont"
      and "endTime \<ge> iniTime"
  assumes "accounts sta \<noteq> [] \<or> cont \<noteq> Close"
    shows "\<exists>txOut. computeTransaction emptyTxAfterDeadline sta cont = TransactionOutput txOut"
  using assms by (meson Timeout.isClosedAndEmpty.elims(2)  timedOutTransaction_closes_contract)

theorem timeOutTransaction_closes_contract2 :
  "validAndPositive_state sta
   \<Longrightarrow> accounts sta \<noteq> [] \<or> cont \<noteq> Close
   \<Longrightarrow> \<exists> inp . isClosedAndEmpty (computeTransaction inp sta cont)"
  by (meson not_less not_less_iff_gr_or_eq timedOutTransaction_closes_contract)

theorem timedOutTransaction_preserves_assets :
  assumes "validAndPositive_state sta"
  assumes "emptyTxAfterDeadline = \<lparr> interval = (iniTime, endTime), inputs = [] \<rparr>"
  assumes "iniTime \<ge> minTime sta"
      and "iniTime \<ge> maxTimeContract cont"
      and "endTime \<ge> iniTime"
  assumes "accounts sta \<noteq> [] \<or> cont \<noteq> Close"
  assumes "computeTransaction emptyTxAfterDeadline sta cont = TransactionOutput txOut"
  shows "assetsInState sta = assetsInExternalPayments (txOutPayments txOut)"
proof -
  note assms
  moreover have "assetsInState sta + assetsInTransaction emptyTxAfterDeadline
          = assetsInState (txOutState txOut) + assetsInExternalPayments (txOutPayments txOut)"
    using computeTransaction_preserves_assets calculation by presburger
  moreover have "accounts (txOutState txOut) = []"
    using calculation by (metis Timeout.isClosedAndEmpty.simps(1) timedOutTransaction_closes_contract)
  ultimately show ?thesis by auto
qed

end


(*  Title:      HOL/Library/Rewrite.thy
    Author:     Christoph Traut, Lars Noschinski, TU Muenchen

Proof method "rewrite" with support for subterm-selection based on patterns.
*)

theory Rewrite
imports Main
begin

consts rewrite_HOLE :: "'a::{}"  ("\<hole>")

lemma eta_expand:
  fixes f :: "'a::{} \<Rightarrow> 'b::{}"
  shows "f \<equiv> \<lambda>x. f x" .

lemma rewr_imp:
  assumes "PROP A \<equiv> PROP B"
  shows "(PROP A \<Longrightarrow> PROP C) \<equiv> (PROP B \<Longrightarrow> PROP C)"
  apply (rule Pure.equal_intr_rule)
  apply (drule equal_elim_rule2[OF assms]; assumption)
  apply (drule equal_elim_rule1[OF assms]; assumption)
  done

lemma imp_cong_eq:
  "(PROP A \<Longrightarrow> (PROP B \<Longrightarrow> PROP C) \<equiv> (PROP B' \<Longrightarrow> PROP C')) \<equiv>
    ((PROP B \<Longrightarrow> PROP A \<Longrightarrow> PROP C) \<equiv> (PROP B' \<Longrightarrow> PROP A \<Longrightarrow> PROP C'))"
  apply (intro Pure.equal_intr_rule)
     apply (drule (1) cut_rl; drule Pure.equal_elim_rule1 Pure.equal_elim_rule2; assumption)+
   apply (drule Pure.equal_elim_rule1 Pure.equal_elim_rule2; assumption)+
  done

ML_file \<open>cconv.ML\<close>
ML_file \<open>rewrite.ML\<close>

end