3807
|
1 |
(*
|
|
2 |
File: MemoryImplementation.ML
|
|
3 |
Author: Stephan Merz
|
|
4 |
Copyright: 1997 University of Munich
|
|
5 |
|
|
6 |
RPC-Memory example: Memory implementation (ML file)
|
|
7 |
|
|
8 |
The main theorem is theorem "Implementation" at the end of this file,
|
|
9 |
which shows that the composition of a reliable memory, an RPC component, and
|
|
10 |
a memory clerk implements an unreliable memory. The files "MIsafe.ML" and
|
|
11 |
"MIlive.ML" contain lower-level lemmas for the safety and liveness parts.
|
|
12 |
|
|
13 |
Steps are (roughly) numbered as in the hand proof.
|
|
14 |
*)
|
|
15 |
|
|
16 |
|
|
17 |
(* ------------------------------ HOL lemmas ------------------------------ *)
|
|
18 |
(* Add the following simple lemmas as default simplification rules. *)
|
|
19 |
|
|
20 |
section "Auxiliary lemmas";
|
|
21 |
|
|
22 |
qed_goal "equal_false_not" HOL.thy "(P = False) = (~P)"
|
|
23 |
(fn _ => [fast_tac prop_cs 1]);
|
|
24 |
|
|
25 |
Addsimps [equal_false_not];
|
|
26 |
|
|
27 |
|
|
28 |
(* A variant of the implication elimination rule that keeps the antecedent.
|
|
29 |
Use "thm RS impdupE" to generate an unsafe (looping) elimination rule.
|
|
30 |
*)
|
|
31 |
|
|
32 |
qed_goal "impdupE" HOL.thy
|
|
33 |
"[| P --> Q; P; [| P;Q |] ==> R |] ==> R"
|
|
34 |
(fn maj::prems => [REPEAT (resolve_tac ([maj RS mp] @ prems) 1)]);
|
|
35 |
|
|
36 |
|
|
37 |
(* Introduction/elimination rules for if-then-else *)
|
|
38 |
|
|
39 |
qed_goal "ifI" HOL.thy
|
|
40 |
"[| Q ==> P(x); ~Q ==> P(y) |] ==> P(if Q then x else y)"
|
|
41 |
(fn prems => [case_tac "Q" 1, ALLGOALS (Asm_simp_tac THEN' (eresolve_tac prems))]);
|
|
42 |
|
|
43 |
qed_goal "ifE" HOL.thy
|
|
44 |
"[| P(if Q then x else y); [| Q; P(x) |] ==> R; [| ~Q; P(y) |] ==> R |] ==> R"
|
|
45 |
(fn (prem1::prems) => [case_tac "Q" 1,
|
|
46 |
ALLGOALS ((cut_facts_tac [prem1])
|
|
47 |
THEN' Asm_full_simp_tac
|
|
48 |
THEN' (REPEAT o ((eresolve_tac prems) ORELSE' atac)))
|
|
49 |
]);
|
|
50 |
|
|
51 |
(* --------------------------- automatic prover --------------------------- *)
|
|
52 |
(* Set up a clasimpset that contains data-level simplifications. *)
|
|
53 |
|
|
54 |
val MI_css = temp_css addsimps2 (CP_simps @ histState.simps
|
|
55 |
@ [slice_def,equal_false_not,if_cancel,sum_case_Inl, sum_case_Inr]);
|
|
56 |
|
|
57 |
(* A more aggressive variant that tries to solve subgoals by assumption
|
|
58 |
or contradiction during the simplification.
|
|
59 |
THIS IS UNSAFE, BECAUSE IT DOESN'T RECORD THE CHOICES!!
|
|
60 |
(but sometimes a lot faster than MI_css)
|
|
61 |
*)
|
|
62 |
val MI_fast_css =
|
|
63 |
let
|
|
64 |
val (cs,ss) = MI_css
|
|
65 |
in
|
|
66 |
(cs, ss addSSolver (fn thms => assume_tac ORELSE' (etac notE)))
|
|
67 |
end;
|
|
68 |
|
|
69 |
(* Make sure the simpset accepts non-boolean simplifications *)
|
|
70 |
simpset := let val (_,ss) = MI_css in ss end;
|
|
71 |
|
|
72 |
|
|
73 |
(****************************** The history variable ******************************)
|
|
74 |
section "History variable";
|
|
75 |
|
|
76 |
qed_goal "HistoryLemma" MemoryImplementation.thy
|
|
77 |
"Init(RALL p. $(ImpInit p)) .& [](RALL p. ImpNext p) \
|
|
78 |
\ .-> (EEX rmhist. Init(RALL p. $(HInit rmhist p)) \
|
|
79 |
\ .& [](RALL p. [HNext rmhist p]_<c p, r p, m p, rmhist@p>))"
|
|
80 |
(fn _ => [Auto_tac(),
|
|
81 |
rtac historyI 1, TRYALL atac,
|
|
82 |
action_simp_tac (!simpset addsimps [HInit_def]) [] [] 1,
|
|
83 |
res_inst_tac [("x","p")] fun_cong 1, atac 1,
|
|
84 |
action_simp_tac (!simpset addsimps [HNext_def]) [busy_squareI] [] 1,
|
|
85 |
res_inst_tac [("x","p")] fun_cong 1, atac 1
|
|
86 |
]);
|
|
87 |
|
|
88 |
qed_goal "History" MemoryImplementation.thy
|
|
89 |
"Implementation .-> (EEX rmhist. Hist rmhist)"
|
|
90 |
(fn _ => [Auto_tac(),
|
|
91 |
rtac ((temp_mp HistoryLemma) RS eex_mono) 1,
|
|
92 |
SELECT_GOAL
|
|
93 |
(auto_tac (MI_css
|
|
94 |
addsimps2 [Impl_def,MClkISpec_def,RPCISpec_def,IRSpec_def,
|
|
95 |
MClkIPSpec_def,RPCIPSpec_def,RPSpec_def,
|
|
96 |
ImpInit_def,Init_def,ImpNext_def,
|
|
97 |
c_def,r_def,m_def,all_box,split_box_conj])) 1,
|
|
98 |
auto_tac (MI_css
|
|
99 |
addsimps2 [Hist_def,HistP_def,Init_def,all_box,split_box_conj])
|
|
100 |
]);
|
|
101 |
|
|
102 |
(******************************** The safety part *********************************)
|
|
103 |
|
|
104 |
section "The safety part";
|
|
105 |
|
|
106 |
(* ------------------------- Include lower-level lemmas ------------------------- *)
|
|
107 |
use "MIsafe.ML";
|
|
108 |
|
|
109 |
section "Correctness of predicate-action diagram";
|
|
110 |
|
|
111 |
(* ========== Step 1.1 ================================================= *)
|
|
112 |
(* The implementation's initial condition implies the state predicate S1 *)
|
|
113 |
|
|
114 |
qed_goal "Step1_1" MemoryImplementation.thy
|
|
115 |
"$(ImpInit p) .& $(HInit rmhist p) .-> $(S1 rmhist p)"
|
|
116 |
(fn _ => [auto_tac (MI_fast_css
|
|
117 |
addsimps2 [MVNROKBA_def,MClkInit_def,RPCInit_def,PInit_def,
|
|
118 |
HInit_def,ImpInit_def,S_def,S1_def])
|
|
119 |
]);
|
|
120 |
|
|
121 |
(* ========== Step 1.2 ================================================== *)
|
|
122 |
(* Figure 16 is a predicate-action diagram for the implementation. *)
|
|
123 |
|
|
124 |
qed_goal "Step1_2_1" MemoryImplementation.thy
|
|
125 |
"[HNext rmhist p]_<c p,r p,m p, rmhist@p> .& ImpNext p \
|
|
126 |
\ .& .~ unchanged <e p, c p, r p, m p, rmhist@p> .& $(S1 rmhist p) \
|
|
127 |
\ .-> (S2 rmhist p)$ .& (ENext p) .& unchanged <c p, r p, m p>"
|
|
128 |
(fn _ => [auto_tac (MI_css addsimps2 [ImpNext_def]
|
|
129 |
addSEs2 [S1ClerkUnchE,S1RPCUnchE,S1MemUnchE,S1HistE]),
|
|
130 |
ALLGOALS (action_simp_tac (!simpset addsimps [square_def]) [] [S1EnvE])
|
|
131 |
]);
|
|
132 |
|
|
133 |
qed_goal "Step1_2_2" MemoryImplementation.thy
|
|
134 |
"[HNext rmhist p]_<c p,r p,m p, rmhist@p> .& ImpNext p \
|
|
135 |
\ .& .~ unchanged <e p, c p, r p, m p, rmhist@p> .& $(S2 rmhist p) \
|
|
136 |
\ .-> (S3 rmhist p)$ .& (MClkFwd memCh crCh cst p) .& unchanged <e p, r p, m p, rmhist@p>"
|
|
137 |
(fn _ => [auto_tac (MI_css addsimps2 [ImpNext_def]
|
|
138 |
addSEs2 [S2EnvUnchE,S2RPCUnchE,S2MemUnchE,S2HistE]),
|
|
139 |
ALLGOALS (action_simp_tac (!simpset addsimps [square_def]) [] [S2ClerkE,S2ForwardE])
|
|
140 |
]);
|
|
141 |
|
|
142 |
qed_goal "Step1_2_3" MemoryImplementation.thy
|
|
143 |
"[HNext rmhist p]_<c p,r p,m p, rmhist@p> .& ImpNext p \
|
|
144 |
\ .& .~ unchanged <e p, c p, r p, m p, rmhist@p> .& $(S3 rmhist p) \
|
|
145 |
\ .-> ((S4 rmhist p)$ .& RPCFwd crCh rmCh rst p .& unchanged <e p, c p, m p, rmhist@p>) \
|
|
146 |
\ .| ((S6 rmhist p)$ .& RPCFail crCh rmCh rst p .& unchanged <e p, c p, m p>)"
|
|
147 |
(fn _ => [action_simp_tac (!simpset addsimps [ImpNext_def])
|
|
148 |
[] [S3EnvUnchE,S3ClerkUnchE,S3MemUnchE] 1,
|
|
149 |
ALLGOALS (action_simp_tac (!simpset addsimps [square_def])
|
|
150 |
[] [S3RPCE,S3ForwardE,S3FailE]),
|
|
151 |
auto_tac (MI_css addEs2 [S3HistE])
|
|
152 |
]);
|
|
153 |
|
|
154 |
qed_goal "Step1_2_4" MemoryImplementation.thy
|
|
155 |
"[HNext rmhist p]_<c p,r p,m p, rmhist@p> .& ImpNext p \
|
|
156 |
\ .& .~ unchanged <e p, c p, r p, m p, rmhist@p> \
|
|
157 |
\ .& $(S4 rmhist p) .& (RALL l. $(MemInv mem l)) \
|
|
158 |
\ .-> ((S4 rmhist p)$ .& Read rmCh mem ires p .& unchanged <e p, c p, r p, rmhist@p>) \
|
|
159 |
\ .| ((S4 rmhist p)$ .& (REX l. Write rmCh mem ires p l) .& unchanged <e p, c p, r p, rmhist@p>) \
|
|
160 |
\ .| ((S5 rmhist p)$ .& MemReturn rmCh ires p .& unchanged <e p, c p, r p>)"
|
|
161 |
(fn _ => [action_simp_tac (!simpset addsimps [ImpNext_def])
|
|
162 |
[] [S4EnvUnchE,S4ClerkUnchE,S4RPCUnchE] 1,
|
|
163 |
ALLGOALS (action_simp_tac (!simpset addsimps [square_def,RNext_def])
|
|
164 |
[] [S4ReadE,S4WriteE,S4ReturnE]),
|
|
165 |
auto_tac (MI_css addEs2 [S4HistE])
|
|
166 |
]);
|
|
167 |
|
|
168 |
qed_goal "Step1_2_5" MemoryImplementation.thy
|
|
169 |
"[HNext rmhist p]_<c p,r p,m p, rmhist@p> .& ImpNext p \
|
|
170 |
\ .& .~ unchanged <e p, c p, r p, m p, rmhist@p> .& $(S5 rmhist p) \
|
|
171 |
\ .-> ((S6 rmhist p)$ .& RPCReply crCh rmCh rst p .& unchanged <e p, c p, m p>) \
|
|
172 |
\ .| ((S6 rmhist p)$ .& RPCFail crCh rmCh rst p .& unchanged <e p, c p, m p>)"
|
|
173 |
(fn _ => [action_simp_tac (!simpset addsimps [ImpNext_def])
|
|
174 |
[] [S5EnvUnchE,S5ClerkUnchE,S5MemUnchE,S5HistE] 1,
|
|
175 |
action_simp_tac (!simpset addsimps [square_def]) [] [S5RPCE] 1,
|
|
176 |
auto_tac (MI_fast_css addSEs2 [S5ReplyE,S5FailE])
|
|
177 |
]);
|
|
178 |
|
|
179 |
qed_goal "Step1_2_6" MemoryImplementation.thy
|
|
180 |
"[HNext rmhist p]_<c p,r p,m p, rmhist@p> .& ImpNext p \
|
|
181 |
\ .& .~ unchanged <e p, c p, r p, m p, rmhist@p> .& $(S6 rmhist p) \
|
|
182 |
\ .-> ((S1 rmhist p)$ .& (MClkReply memCh crCh cst p) .& unchanged <e p, r p, m p>)\
|
|
183 |
\ .| ((S3 rmhist p)$ .& (MClkRetry memCh crCh cst p) .& unchanged <e p,r p,m p,rmhist@p>)"
|
|
184 |
(fn _ => [action_simp_tac (!simpset addsimps [ImpNext_def])
|
|
185 |
[] [S6EnvUnchE,S6RPCUnchE,S6MemUnchE] 1,
|
|
186 |
ALLGOALS (action_simp_tac (!simpset addsimps [square_def])
|
|
187 |
[] [S6ClerkE,S6RetryE,S6ReplyE]),
|
|
188 |
auto_tac (MI_css addEs2 [S6HistE])
|
|
189 |
]);
|
|
190 |
|
|
191 |
|
|
192 |
(* --------------------------------------------------------------------------
|
|
193 |
Step 1.3: S1 implies the barred initial condition.
|
|
194 |
*)
|
|
195 |
|
|
196 |
section "Initialization (Step 1.3)";
|
|
197 |
|
|
198 |
val resbar_unl = rewrite_rule [slice_def] (action_unlift resbar_def);
|
|
199 |
|
|
200 |
qed_goal "Step1_3" MemoryImplementation.thy
|
|
201 |
"$(S1 rmhist p) .-> $(PInit (resbar rmhist) p)"
|
|
202 |
(fn _ => [action_simp_tac (!simpset addsimps [resbar_unl,PInit_def,S_def,S1_def])
|
|
203 |
[] [] 1
|
|
204 |
]);
|
|
205 |
|
|
206 |
(* ----------------------------------------------------------------------
|
|
207 |
Step 1.4: Implementation's next-state relation simulates specification's
|
|
208 |
next-state relation (with appropriate substitutions)
|
|
209 |
*)
|
|
210 |
|
|
211 |
section "Step simulation (Step 1.4)";
|
|
212 |
|
|
213 |
qed_goal "Step1_4_1" MemoryImplementation.thy
|
|
214 |
"ENext p .& $(S1 rmhist p) .& (S2 rmhist p)$ .& unchanged <c p, r p, m p> \
|
|
215 |
\ .-> unchanged <rtrner memCh @ p, resbar rmhist @ p>"
|
|
216 |
(fn _ => [ auto_tac (MI_fast_css addsimps2 [c_def,r_def,m_def,resbar_unl]) ]);
|
|
217 |
|
|
218 |
qed_goal "Step1_4_2" MemoryImplementation.thy
|
|
219 |
"MClkFwd memCh crCh cst p .& $(S2 rmhist p) .& (S3 rmhist p)$ \
|
|
220 |
\ .& unchanged <e p, r p, m p, rmhist@p> \
|
|
221 |
\ .-> unchanged <rtrner memCh @ p, resbar rmhist @ p>"
|
|
222 |
(fn _ => [auto_tac (MI_fast_css
|
|
223 |
addsimps2 [MClkFwd_def, e_def, r_def, m_def, resbar_unl,
|
|
224 |
S_def, S2_def, S3_def])
|
|
225 |
]);
|
|
226 |
|
|
227 |
qed_goal "Step1_4_3a" MemoryImplementation.thy
|
|
228 |
"RPCFwd crCh rmCh rst p .& $(S3 rmhist p) .& (S4 rmhist p)$ \
|
|
229 |
\ .& unchanged <e p, c p, m p, rmhist@p> \
|
|
230 |
\ .-> unchanged <rtrner memCh @ p, resbar rmhist @ p>"
|
|
231 |
(fn _ => [auto_tac (MI_fast_css addsimps2 [e_def,c_def,m_def,resbar_unl]),
|
|
232 |
(* NB: Adding S3_exclE,S4_exclE as safe elims above would loop,
|
|
233 |
adding them as unsafe elims doesn't help,
|
|
234 |
because auto_tac doesn't find the proof! *)
|
|
235 |
REPEAT (eresolve_tac [S3_exclE,S4_exclE] 1),
|
|
236 |
action_simp_tac (!simpset addsimps [S_def, S3_def]) [] [] 1
|
|
237 |
]);
|
|
238 |
|
|
239 |
qed_goal "Step1_4_3b" MemoryImplementation.thy
|
|
240 |
"RPCFail crCh rmCh rst p .& $(S3 rmhist p) .& (S6 rmhist p)$ .& unchanged <e p, c p, m p>\
|
|
241 |
\ .-> MemFail memCh (resbar rmhist) p"
|
|
242 |
(fn _ => [auto_tac (MI_css addsimps2 [RPCFail_def,MemFail_def,e_def,c_def,m_def,
|
|
243 |
resbar_unl]),
|
|
244 |
(* It's faster not to expand S3 at once *)
|
|
245 |
action_simp_tac (!simpset addsimps [S3_def,S_def]) [] [] 1,
|
|
246 |
etac S6_exclE 1,
|
|
247 |
auto_tac (MI_fast_css addsimps2 [Return_def])
|
|
248 |
]);
|
|
249 |
|
|
250 |
|
|
251 |
qed_goal "Step1_4_4a1" MemoryImplementation.thy
|
|
252 |
"$(S4 rmhist p) .& (S4 rmhist p)$ .& ReadInner rmCh mem ires p l \
|
|
253 |
\ .& unchanged <e p, c p, r p, rmhist@p> .& $(MemInv mem l) \
|
|
254 |
\ .-> ReadInner memCh mem (resbar rmhist) p l"
|
|
255 |
(fn _ => [action_simp_tac
|
|
256 |
(!simpset addsimps [ReadInner_def,GoodRead_def,BadRead_def,e_def,c_def,m_def])
|
|
257 |
[] [] 1,
|
|
258 |
ALLGOALS (REPEAT o (etac S4_exclE)),
|
|
259 |
auto_tac (MI_css addsimps2 [resbar_unl]),
|
|
260 |
ALLGOALS (action_simp_tac
|
|
261 |
(!simpset addsimps [RPCRelayArg_def,MClkRelayArg_def,
|
|
262 |
S_def,S4_def,RdRequest_def,MemInv_def])
|
|
263 |
[] [impE,MemValNotAResultE])
|
|
264 |
]);
|
|
265 |
|
|
266 |
qed_goal "Step1_4_4a" MemoryImplementation.thy
|
|
267 |
"Read rmCh mem ires p .& $(S4 rmhist p) .& (S4 rmhist p)$ \
|
|
268 |
\ .& unchanged <e p, c p, r p, rmhist@p> .& (RALL l. $(MemInv mem l)) \
|
|
269 |
\ .-> Read memCh mem (resbar rmhist) p"
|
|
270 |
(fn _ => [ auto_tac (MI_css addsimps2 [Read_def] addSIs2 [action_mp Step1_4_4a1]) ]);
|
|
271 |
|
|
272 |
qed_goal "Step1_4_4b1" MemoryImplementation.thy
|
|
273 |
"$(S4 rmhist p) .& (S4 rmhist p)$ .& WriteInner rmCh mem ires p l v \
|
|
274 |
\ .& unchanged <e p, c p, r p, rmhist@p> \
|
|
275 |
\ .-> WriteInner memCh mem (resbar rmhist) p l v"
|
|
276 |
(fn _ => [action_simp_tac
|
|
277 |
(!simpset addsimps [WriteInner_def, GoodWrite_def, BadWrite_def,
|
|
278 |
e_def, c_def, m_def])
|
|
279 |
[] [] 1,
|
|
280 |
ALLGOALS (REPEAT o (etac S4_exclE)),
|
|
281 |
auto_tac (MI_css addsimps2 [resbar_unl]),
|
|
282 |
(* it's faster not to merge the two simplifications *)
|
|
283 |
ALLGOALS (action_simp_tac
|
|
284 |
(!simpset addsimps [RPCRelayArg_def,MClkRelayArg_def,
|
|
285 |
S_def,S4_def,WrRequest_def])
|
|
286 |
[] [])
|
|
287 |
]);
|
|
288 |
|
|
289 |
qed_goal "Step1_4_4b" MemoryImplementation.thy
|
|
290 |
"Write rmCh mem ires p l .& $(S4 rmhist p) .& (S4 rmhist p)$ \
|
|
291 |
\ .& unchanged <e p, c p, r p, rmhist@p> \
|
|
292 |
\ .-> Write memCh mem (resbar rmhist) p l"
|
|
293 |
(fn _ => [ auto_tac (MI_css addsimps2 [Write_def] addSIs2 [action_mp Step1_4_4b1]) ]);
|
|
294 |
|
|
295 |
qed_goal "Step1_4_4c" MemoryImplementation.thy
|
|
296 |
"MemReturn rmCh ires p .& $(S4 rmhist p) .& (S5 rmhist p)$ .& unchanged <e p, c p, r p> \
|
|
297 |
\ .-> unchanged <rtrner memCh @ p, resbar rmhist @ p>"
|
|
298 |
(fn _ => [action_simp_tac
|
|
299 |
(!simpset addsimps [e_def,c_def,r_def,resbar_unl]) [] [] 1,
|
|
300 |
REPEAT (eresolve_tac [S4_exclE,S5_exclE] 1),
|
|
301 |
auto_tac (MI_fast_css addsimps2 [MemReturn_def,Return_def])
|
|
302 |
]);
|
|
303 |
|
|
304 |
qed_goal "Step1_4_5a" MemoryImplementation.thy
|
|
305 |
"RPCReply crCh rmCh rst p .& $(S5 rmhist p) .& (S6 rmhist p)$ .& unchanged <e p, c p, m p> \
|
|
306 |
\ .-> unchanged <rtrner memCh @ p, resbar rmhist @ p>"
|
|
307 |
(fn _ => [auto_tac (MI_css addsimps2 [e_def,c_def,m_def, resbar_unl]),
|
|
308 |
REPEAT (eresolve_tac [S5_exclE,S6_exclE] 1),
|
|
309 |
auto_tac (MI_css addsimps2 [RPCReply_def,Return_def,S5_def,S_def]
|
|
310 |
addSEs2 [MVOKBAnotRFE])
|
|
311 |
]);
|
|
312 |
|
|
313 |
qed_goal "Step1_4_5b" MemoryImplementation.thy
|
|
314 |
"RPCFail crCh rmCh rst p .& $(S5 rmhist p) .& (S6 rmhist p)$ .& unchanged <e p, c p, m p>\
|
|
315 |
\ .-> MemFail memCh (resbar rmhist) p"
|
|
316 |
(fn _ => [action_simp_tac
|
|
317 |
(!simpset addsimps [e_def, c_def, m_def, RPCFail_def, Return_def,
|
|
318 |
MemFail_def, resbar_unl])
|
|
319 |
[] [] 1,
|
|
320 |
action_simp_tac (!simpset addsimps [S5_def,S_def]) [] [] 1,
|
|
321 |
etac S6_exclE 1,
|
|
322 |
auto_tac MI_css
|
|
323 |
]);
|
|
324 |
|
|
325 |
qed_goal "Step1_4_6a" MemoryImplementation.thy
|
|
326 |
"MClkReply memCh crCh cst p .& $(S6 rmhist p) .& (S1 rmhist p)$ .& unchanged <e p, r p, m p> \
|
|
327 |
\ .-> MemReturn memCh (resbar rmhist) p"
|
|
328 |
(fn _ => [action_simp_tac
|
|
329 |
(!simpset addsimps [e_def, r_def, m_def, MClkReply_def, MemReturn_def,
|
|
330 |
Return_def, resbar_unl])
|
|
331 |
[] [] 1,
|
|
332 |
ALLGOALS (etac S6_exclE),
|
|
333 |
ALLGOALS Asm_full_simp_tac, (* simplify if-then-else *)
|
|
334 |
ALLGOALS (action_simp_tac
|
|
335 |
(!simpset addsimps [MClkReplyVal_def,S6_def,S_def])
|
|
336 |
[] []),
|
|
337 |
rtac ifI 1,
|
|
338 |
ALLGOALS (action_simp_tac (!simpset) [] [MVOKBARFnotNRE])
|
|
339 |
]);
|
|
340 |
|
|
341 |
qed_goal "Step1_4_6b" MemoryImplementation.thy
|
|
342 |
"MClkRetry memCh crCh cst p .& $(S6 rmhist p) .& (S3 rmhist p)$ \
|
|
343 |
\ .& unchanged <e p, r p, m p, rmhist@p> \
|
|
344 |
\ .-> MemFail memCh (resbar rmhist) p"
|
|
345 |
(fn _ => [action_simp_tac
|
|
346 |
(!simpset addsimps [e_def, r_def, m_def, MClkRetry_def, MemFail_def, resbar_unl])
|
|
347 |
[] [] 1,
|
|
348 |
SELECT_GOAL (auto_tac (MI_css addsimps2 [S6_def,S_def])) 1,
|
|
349 |
etac S3_exclE 1,
|
|
350 |
Asm_full_simp_tac 1,
|
|
351 |
action_simp_tac (!simpset addsimps [S6_def,S3_def,S_def]) [] [] 1
|
|
352 |
]);
|
|
353 |
|
|
354 |
qed_goal "S_lemma" MemoryImplementation.thy
|
|
355 |
"unchanged <e p, c p, r p, m p, rmhist@p> \
|
|
356 |
\ .-> unchanged (S rmhist ec cc rc cs rs hs1 hs2 p)"
|
|
357 |
(fn _ => [auto_tac (MI_css addsimps2 [e_def,c_def,r_def,m_def,caller_def,rtrner_def,
|
|
358 |
S_def,Calling_def])
|
|
359 |
]);
|
|
360 |
|
|
361 |
qed_goal "Step1_4_7H" MemoryImplementation.thy
|
|
362 |
"unchanged <e p, c p, r p, m p, rmhist@p> \
|
|
363 |
\ .-> unchanged <rtrner memCh @ p, S1 rmhist p, S2 rmhist p, S3 rmhist p, \
|
|
364 |
\ S4 rmhist p, S5 rmhist p, S6 rmhist p>"
|
|
365 |
(fn _ => [Action_simp_tac 1,
|
|
366 |
SELECT_GOAL (auto_tac (MI_fast_css addsimps2 [c_def])) 1,
|
|
367 |
ALLGOALS (simp_tac (!simpset
|
|
368 |
addsimps [S1_def,S2_def,S3_def,S4_def,S5_def,S6_def])),
|
|
369 |
auto_tac (MI_css addSIs2 [action_mp S_lemma])
|
|
370 |
]);
|
|
371 |
|
|
372 |
(* unlifted version as elimination rule *)
|
|
373 |
bind_thm("Step1_4_7h",
|
|
374 |
(rewrite_rule action_rews (Step1_4_7H RS actionD)) RS impdupE);
|
|
375 |
|
|
376 |
qed_goal "Step1_4_7" MemoryImplementation.thy
|
|
377 |
"unchanged <e p, c p, r p, m p, rmhist@p> .-> unchanged <rtrner memCh @ p, resbar rmhist @ p>"
|
|
378 |
(fn _ => [rtac actionI 1,
|
|
379 |
rewrite_goals_tac action_rews,
|
|
380 |
rtac impI 1,
|
|
381 |
etac Step1_4_7h 1,
|
|
382 |
auto_tac (MI_css addsimps2 [e_def,c_def,r_def,m_def,rtrner_def,resbar_unl])
|
|
383 |
]);
|
|
384 |
|
|
385 |
|
|
386 |
(* Frequently needed abbreviation: distinguish between idling and non-idling
|
|
387 |
steps of the implementation, and try to solve the idling case by simplification
|
|
388 |
*)
|
|
389 |
fun split_idle_tac simps i =
|
|
390 |
EVERY [rtac actionI i,
|
|
391 |
case_tac "(unchanged <e p, c p, r p, m p, rmhist@p>) [[s,t]]" i,
|
|
392 |
rewrite_goals_tac action_rews,
|
|
393 |
etac Step1_4_7h i,
|
|
394 |
asm_full_simp_tac (!simpset addsimps simps) i
|
|
395 |
];
|
|
396 |
|
|
397 |
(* ----------------------------------------------------------------------
|
|
398 |
Combine steps 1.2 and 1.4 to prove that the implementation satisfies
|
|
399 |
the specification's next-state relation.
|
|
400 |
*)
|
|
401 |
|
|
402 |
(* Steps that leave all variables unchanged are safe, so I may assume
|
|
403 |
that some variable changes in the proof that a step is safe. *)
|
|
404 |
qed_goal "unchanged_safe" MemoryImplementation.thy
|
|
405 |
"(.~ (unchanged <e p, c p, r p, m p, rmhist@p>) \
|
|
406 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>) \
|
|
407 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
408 |
(fn _ => [rtac actionI 1,
|
|
409 |
case_tac "(unchanged <e p, c p, r p, m p, rmhist@p>) [[s,t]]" 1,
|
|
410 |
rewrite_goals_tac action_rews,
|
|
411 |
auto_tac (MI_css addsimps2 [square_def] addSEs2 [action_impE Step1_4_7])
|
|
412 |
]);
|
|
413 |
(* turn into (unsafe, looping!) introduction rule *)
|
|
414 |
bind_thm("unchanged_safeI", impI RS (action_mp unchanged_safe));
|
|
415 |
|
|
416 |
qed_goal "S1safe" MemoryImplementation.thy
|
|
417 |
"$(S1 rmhist p) .& ImpNext p .& [HNext rmhist p]_<c p,r p,m p, rmhist@p> \
|
|
418 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
419 |
(fn _ => [Action_simp_tac 1,
|
|
420 |
rtac unchanged_safeI 1,
|
|
421 |
rtac idle_squareI 1,
|
|
422 |
auto_tac (MI_css addSEs2 (map action_conjimpE [Step1_2_1,Step1_4_1]))
|
|
423 |
]);
|
|
424 |
|
|
425 |
qed_goal "S2safe" MemoryImplementation.thy
|
|
426 |
"$(S2 rmhist p) .& ImpNext p .& [HNext rmhist p]_<c p,r p,m p, rmhist@p> \
|
|
427 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
428 |
(fn _ => [Action_simp_tac 1,
|
|
429 |
rtac unchanged_safeI 1,
|
|
430 |
rtac idle_squareI 1,
|
|
431 |
auto_tac (MI_fast_css addSEs2 (map action_conjimpE [Step1_2_2,Step1_4_2]))
|
|
432 |
]);
|
|
433 |
|
|
434 |
qed_goal "S3safe" MemoryImplementation.thy
|
|
435 |
"$(S3 rmhist p) .& ImpNext p .& [HNext rmhist p]_<c p,r p,m p, rmhist@p> \
|
|
436 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
437 |
(fn _ => [Action_simp_tac 1,
|
|
438 |
rtac unchanged_safeI 1,
|
|
439 |
auto_tac (MI_css addSEs2 [action_conjimpE Step1_2_3]),
|
|
440 |
auto_tac (MI_fast_css addsimps2 [square_def,UNext_def]
|
|
441 |
addSEs2 (map action_conjimpE [Step1_4_3a,Step1_4_3b]))
|
|
442 |
]);
|
|
443 |
|
|
444 |
qed_goal "S4safe" MemoryImplementation.thy
|
|
445 |
"$(S4 rmhist p) .& ImpNext p .& [HNext rmhist p]_<c p,r p,m p, rmhist@p> \
|
|
446 |
\ .& (RALL l. $(MemInv mem l)) \
|
|
447 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
448 |
(fn _ => [Action_simp_tac 1,
|
|
449 |
rtac unchanged_safeI 1,
|
|
450 |
auto_tac (MI_css addSEs2 [action_conjimpE Step1_2_4]),
|
|
451 |
ALLGOALS (action_simp_tac (!simpset addsimps [square_def,UNext_def,RNext_def]) [] []),
|
|
452 |
auto_tac (MI_fast_css addSEs2 (map action_conjimpE
|
|
453 |
[Step1_4_4a,Step1_4_4b,Step1_4_4c]))
|
|
454 |
]);
|
|
455 |
|
|
456 |
qed_goal "S5safe" MemoryImplementation.thy
|
|
457 |
"$(S5 rmhist p) .& ImpNext p .& [HNext rmhist p]_<c p,r p,m p, rmhist@p> \
|
|
458 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
459 |
(fn _ => [Action_simp_tac 1,
|
|
460 |
rtac unchanged_safeI 1,
|
|
461 |
auto_tac (MI_css addSEs2 [action_conjimpE Step1_2_5]),
|
|
462 |
auto_tac (MI_fast_css addsimps2 [square_def,UNext_def]
|
|
463 |
addSEs2 (map action_conjimpE [Step1_4_5a,Step1_4_5b]))
|
|
464 |
]);
|
|
465 |
|
|
466 |
qed_goal "S6safe" MemoryImplementation.thy
|
|
467 |
"$(S6 rmhist p) .& ImpNext p .& [HNext rmhist p]_<c p,r p,m p, rmhist@p> \
|
|
468 |
\ .-> [UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
469 |
(fn _ => [Action_simp_tac 1,
|
|
470 |
rtac unchanged_safeI 1,
|
|
471 |
auto_tac (MI_css addSEs2 [action_conjimpE Step1_2_6]),
|
|
472 |
auto_tac (MI_fast_css addsimps2 [square_def,UNext_def,RNext_def]
|
|
473 |
addSEs2 (map action_conjimpE [Step1_4_6a,Step1_4_6b]))
|
|
474 |
]);
|
|
475 |
|
|
476 |
(* ----------------------------------------------------------------------
|
|
477 |
Step 1.5: Temporal refinement proof, based on previous steps.
|
|
478 |
*)
|
|
479 |
|
|
480 |
section "The liveness part";
|
|
481 |
|
|
482 |
use "MIlive.ML";
|
|
483 |
|
|
484 |
section "Refinement proof (step 1.5)";
|
|
485 |
|
|
486 |
(* Prove invariants of the implementation:
|
|
487 |
a. memory invariant
|
|
488 |
b. "implementation invariant": always in states S1,...,S6
|
|
489 |
*)
|
|
490 |
qed_goal "Step1_5_1a" MemoryImplementation.thy
|
|
491 |
"IPImp p .-> (RALL l. []$(MemInv mem l))"
|
|
492 |
(fn _ => [auto_tac (MI_css addsimps2 [IPImp_def]
|
|
493 |
addSIs2 [temp_mp MemoryInvariantAll])
|
|
494 |
]);
|
|
495 |
bind_thm("MemInvI", (rewrite_rule intensional_rews (Step1_5_1a RS tempD)) RS impdupE);
|
|
496 |
|
|
497 |
qed_goal "Step1_5_1b" MemoryImplementation.thy
|
|
498 |
" Init($(ImpInit p) .& $(HInit rmhist p)) .& [](ImpNext p) \
|
|
499 |
\ .& [][HNext rmhist p]_<c p, r p, m p, rmhist@p> .& [](RALL l. $(MemInv mem l)) \
|
|
500 |
\ .-> []($(ImpInv rmhist p))"
|
|
501 |
(fn _ => [inv_tac MI_css 1,
|
|
502 |
auto_tac (MI_css
|
|
503 |
addsimps2 [Init_def, ImpInv_def]
|
|
504 |
addSEs2 [action_impE Step1_1]
|
|
505 |
addEs2 (map action_conjimpE
|
|
506 |
[S1_successors,S2_successors,S3_successors,
|
|
507 |
S4_successors,S5_successors,S6_successors]))
|
|
508 |
]);
|
|
509 |
bind_thm("ImpInvI", (rewrite_rule intensional_rews (Step1_5_1b RS tempD)) RS impdupE);
|
|
510 |
|
|
511 |
(*** Initialization ***)
|
|
512 |
qed_goal "Step1_5_2a" MemoryImplementation.thy
|
|
513 |
"Init($(ImpInit p) .& $(HInit rmhist p)) .-> Init($PInit (resbar rmhist) p)"
|
|
514 |
(fn _ => [auto_tac (MI_css addsimps2 [Init_def]
|
|
515 |
addSIs2 (map action_mp [Step1_1,Step1_3]))
|
|
516 |
]);
|
|
517 |
|
|
518 |
(*** step simulation ***)
|
|
519 |
qed_goal "Step1_5_2b" MemoryImplementation.thy
|
|
520 |
"[](ImpNext p .& [HNext rmhist p]_<c p, r p, m p, rmhist@p> \
|
|
521 |
\ .& $(ImpInv rmhist p) .& (RALL l. $(MemInv mem l))) \
|
|
522 |
\ .-> [][UNext memCh mem (resbar rmhist) p]_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
523 |
(fn _ => [auto_tac (MI_fast_css
|
|
524 |
addsimps2 [ImpInv_def]
|
|
525 |
addSEs2 (STL4E::(map action_conjimpE
|
|
526 |
[S1safe,S2safe,S3safe,S4safe,S5safe,S6safe])))
|
|
527 |
]);
|
|
528 |
|
|
529 |
|
|
530 |
(*** Liveness ***)
|
|
531 |
qed_goal "GoodImpl" MemoryImplementation.thy
|
|
532 |
"IPImp p .& HistP rmhist p \
|
|
533 |
\ .-> Init($(ImpInit p) .& $(HInit rmhist p)) \
|
|
534 |
\ .& [](ImpNext p .& [HNext rmhist p]_<c p, r p, m p, rmhist@p>) \
|
|
535 |
\ .& [](RALL l. $(MemInv mem l)) .& []($(ImpInv rmhist p)) \
|
|
536 |
\ .& ImpLive p"
|
|
537 |
(fn _ => [(* need some subgoals to prove [](ImpInv p), avoid duplication *)
|
|
538 |
rtac tempI 1, rewrite_goals_tac intensional_rews, rtac impI 1,
|
|
539 |
subgoal_tac
|
|
540 |
"sigma |= Init($(ImpInit p) .& $(HInit rmhist p)) \
|
|
541 |
\ .& [](ImpNext p) \
|
|
542 |
\ .& [][HNext rmhist p]_<c p, r p, m p, rmhist@p> \
|
|
543 |
\ .& [](RALL l. $(MemInv mem l))" 1,
|
|
544 |
auto_tac (MI_css addsimps2 [split_box_conj]
|
|
545 |
addSEs2 [temp_conjimpE Step1_5_1b]),
|
|
546 |
SELECT_GOAL
|
|
547 |
(auto_tac (MI_css addsimps2 [IPImp_def,MClkIPSpec_def,RPCIPSpec_def,RPSpec_def,
|
|
548 |
ImpLive_def,c_def,r_def,m_def])) 1,
|
|
549 |
SELECT_GOAL
|
|
550 |
(auto_tac (MI_css addsimps2 [IPImp_def,MClkIPSpec_def,RPCIPSpec_def,RPSpec_def,
|
|
551 |
HistP_def,Init_def,action_unlift ImpInit_def])) 1,
|
|
552 |
SELECT_GOAL
|
|
553 |
(auto_tac (MI_css addsimps2 [IPImp_def,MClkIPSpec_def,RPCIPSpec_def,RPSpec_def,
|
|
554 |
ImpNext_def,c_def,r_def,m_def,
|
|
555 |
split_box_conj])) 1,
|
|
556 |
SELECT_GOAL (auto_tac (MI_css addsimps2 [HistP_def])) 1,
|
|
557 |
etac ((temp_mp Step1_5_1a) RS ((temp_unlift allT) RS iffD1)) 1
|
|
558 |
]);
|
|
559 |
|
|
560 |
(* The implementation is infinitely often in state S1 *)
|
|
561 |
qed_goal "Step1_5_3a" MemoryImplementation.thy
|
|
562 |
"[](ImpNext p .& [HNext rmhist p]_<c p, r p, m p, rmhist@p>) \
|
|
563 |
\ .& [](RALL l. $(MemInv mem l)) \
|
|
564 |
\ .& []($(ImpInv rmhist p)) .& ImpLive p \
|
|
565 |
\ .-> []<>($(S1 rmhist p))"
|
|
566 |
(fn _ => [auto_tac (MI_css addsimps2 [ImpLive_def]),
|
|
567 |
rtac S1Infinite 1,
|
|
568 |
SELECT_GOAL
|
|
569 |
(auto_tac (MI_css
|
|
570 |
addsimps2 [split_box_conj]
|
|
571 |
addSIs2 (NotS1LeadstoS6::
|
|
572 |
map temp_mp [S2_live,S3_live,S4a_live,S4b_live,S5_live]))) 1,
|
|
573 |
auto_tac (MI_css addsimps2 [split_box_conj] addSIs2 [temp_mp S6_live])
|
|
574 |
]);
|
|
575 |
|
|
576 |
(* Hence, it satisfies the fairness requirements of the specification *)
|
|
577 |
qed_goal "Step1_5_3b" MemoryImplementation.thy
|
|
578 |
"[](ImpNext p .& [HNext rmhist p]_<c p, r p, m p, rmhist@p>) \
|
|
579 |
\ .& [](RALL l. $(MemInv mem l)) .& []($(ImpInv rmhist p)) .& ImpLive p \
|
|
580 |
\ .-> WF(RNext memCh mem (resbar rmhist) p)_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
581 |
(fn _ => [ auto_tac (MI_fast_css addSIs2 [RNext_fair,temp_mp Step1_5_3a]) ]);
|
|
582 |
|
|
583 |
qed_goal "Step1_5_3c" MemoryImplementation.thy
|
|
584 |
"[](ImpNext p .& [HNext rmhist p]_<c p, r p, m p, rmhist@p>) \
|
|
585 |
\ .& [](RALL l. $(MemInv mem l)) .& []($(ImpInv rmhist p)) .& ImpLive p \
|
|
586 |
\ .-> WF(MemReturn memCh (resbar rmhist) p)_<rtrner memCh @ p, resbar rmhist @ p>"
|
|
587 |
(fn _ => [ auto_tac (MI_fast_css addSIs2 [Return_fair,temp_mp Step1_5_3a]) ]);
|
|
588 |
|
|
589 |
|
|
590 |
(* QED step of step 1 *)
|
|
591 |
qed_goal "Step1" MemoryImplementation.thy
|
|
592 |
"IPImp p .& HistP rmhist p .-> UPSpec memCh mem (resbar rmhist) p"
|
|
593 |
(fn _ => [auto_tac
|
|
594 |
(MI_css addsimps2 [UPSpec_def,split_box_conj]
|
|
595 |
addSEs2 [temp_impE GoodImpl]
|
|
596 |
addSIs2 (map temp_mp [Step1_5_2a,Step1_5_2b,
|
|
597 |
Step1_5_3b,Step1_5_3c]))
|
|
598 |
]);
|
|
599 |
|
|
600 |
|
|
601 |
(* ------------------------------ Step 2 ------------------------------ *)
|
|
602 |
section "Step 2";
|
|
603 |
|
|
604 |
qed_goal "Step2_2a" MemoryImplementation.thy
|
|
605 |
"ImpNext p .& [HNext rmhist p]_<c p, r p, m p, rmhist@p> \
|
|
606 |
\ .& $(S4 rmhist p) .& Write rmCh mem ires p l \
|
|
607 |
\ .-> (S4 rmhist p)$ .& unchanged <e p, c p, r p, rmhist@p>"
|
|
608 |
(fn _ => [split_idle_tac [] 1,
|
|
609 |
action_simp_tac (!simpset addsimps [ImpNext_def])
|
|
610 |
[] [S4EnvUnchE,S4ClerkUnchE,S4RPCUnchE] 1,
|
|
611 |
TRYALL (action_simp_tac (!simpset addsimps [square_def]) [] [S4WriteE]),
|
|
612 |
Auto_tac()
|
|
613 |
]);
|
|
614 |
|
|
615 |
qed_goal "Step2_2" MemoryImplementation.thy
|
|
616 |
" (RALL p. ImpNext p) \
|
|
617 |
\ .& (RALL p. [HNext rmhist p]_<c p, r p, m p, rmhist@p>) \
|
|
618 |
\ .& (RALL p. $(ImpInv rmhist p)) \
|
|
619 |
\ .& [REX q. Write rmCh mem ires q l]_(mem@l) \
|
|
620 |
\ .-> [REX q. Write memCh mem (resbar rmhist) q l]_(mem@l)"
|
|
621 |
(fn _ => [auto_tac (MI_css addsimps2 [square_def]
|
|
622 |
addSIs2 [action_mp Step1_4_4b]
|
|
623 |
addSEs2 [WriteS4E, action_conjimpE Step2_2a])
|
|
624 |
]);
|
|
625 |
|
|
626 |
qed_goal "Step2_lemma" MemoryImplementation.thy
|
|
627 |
" []( (RALL p. ImpNext p) \
|
|
628 |
\ .& (RALL p. [HNext rmhist p]_<c p, r p, m p, rmhist@p>) \
|
|
629 |
\ .& (RALL p. $(ImpInv rmhist p)) \
|
|
630 |
\ .& [REX q. Write rmCh mem ires q l]_(mem@l)) \
|
|
631 |
\ .-> [][REX q. Write memCh mem (resbar rmhist) q l]_(mem@l)"
|
|
632 |
(fn _ => [ auto_tac (MI_css addSEs2 [STL4E, action_conjimpE Step2_2]) ]);
|
|
633 |
|
|
634 |
qed_goal "Step2" MemoryImplementation.thy
|
|
635 |
"#(MemLoc l) .& (RALL p. IPImp p .& HistP rmhist p) \
|
|
636 |
\ .-> MSpec memCh mem (resbar rmhist) l"
|
|
637 |
(fn _ => [auto_tac (MI_css addsimps2 [MSpec_def]),
|
|
638 |
(* prove initial condition, don't expand IPImp in other subgoal *)
|
|
639 |
SELECT_GOAL (auto_tac (MI_css addsimps2 [IPImp_def,MSpec_def])) 1,
|
|
640 |
auto_tac (MI_css addSIs2 [temp_mp Step2_lemma]
|
|
641 |
addsimps2 [split_box_conj,all_box]),
|
|
642 |
SELECT_GOAL (auto_tac (MI_css addsimps2 [IPImp_def,MSpec_def])) 4,
|
|
643 |
auto_tac (MI_css addsimps2 [split_box_conj]
|
|
644 |
addSEs2 [temp_impE GoodImpl])
|
|
645 |
]);
|
|
646 |
|
|
647 |
(* ----------------------------- Main theorem --------------------------------- *)
|
|
648 |
section "Memory implementation";
|
|
649 |
|
|
650 |
(* The combination of a legal caller, the memory clerk, the RPC component,
|
|
651 |
and a reliable memory implement the unreliable memory.
|
|
652 |
*)
|
|
653 |
|
|
654 |
(* Implementation of internal specification by combination of implementation
|
|
655 |
and history variable with explicit refinement mapping
|
|
656 |
*)
|
|
657 |
qed_goal "Impl_IUSpec" MemoryImplementation.thy
|
|
658 |
"Implementation .& Hist rmhist .-> IUSpec memCh mem (resbar rmhist)"
|
|
659 |
(fn _ => [auto_tac (MI_css addsimps2 [IUSpec_def,Impl_def,IPImp_def,MClkISpec_def,
|
|
660 |
RPCISpec_def,IRSpec_def,Hist_def]
|
|
661 |
addSIs2 (map temp_mp [Step1,Step2]))
|
|
662 |
]);
|
|
663 |
|
|
664 |
(* The main theorem: introduce hiding and eliminate history variable. *)
|
|
665 |
qed_goal "Implementation" MemoryImplementation.thy
|
|
666 |
"Implementation .-> USpec memCh"
|
|
667 |
(fn _ => [Auto_tac(),
|
|
668 |
forward_tac [temp_mp History] 1,
|
|
669 |
auto_tac (MI_css addsimps2 [USpec_def]
|
|
670 |
addIs2 (map temp_mp [eexI, Impl_IUSpec])
|
|
671 |
addSEs2 [eexE])
|
|
672 |
]);
|