ai-free / backend /cortexm0 /CM0 /SimCtl.lean
SNAPKITTYWEST's picture
Sync from GitHub at 25c8330: hardware-in-the-loop rig, SAM D21 board, guard elimination on RV32/Cortex-M3
0e9783b verified
Raw History Blame Contribute Delete
12.7 kB
import CM0.SimDiv
/-!
# CM0.SimCtl
Control flow: `jmp branch call ret halt`. IR `call` and `ret` are the model's `call` and `ret`
(fixed sequences on `sp`, see `CM0.Isa`), so the IR return stack is the return stack
(`.rstack`) below `sp0`, related by `RsRel` (cells hold the ARMv6-M code index of the return
instruction).
-/
namespace WordDialect
namespace CM0
open Reg
theorem offs_succ (cf : Nat → Facts) {p : Prog 32} {k : Nat} {i : WordDialect.Instr 32}
(h : p[k]? = some i) : offs cf p (k + 1) = offs cf p k + isize (cf k) i := by
induction p generalizing cf k with
| nil => simp at h
| cons j js ih =>
cases k with
| zero => simp at h; subst h; simp [offs_cons, offs_zero]
| succ k =>
simp only [List.getElem?_cons_succ] at h
rw [offs_cons, offs_cons, ih (fun j => cf (j + 1)) h]; omega
section Ctl
variable {c : Cfg} {p : Prog 32} {s : State 32} {x : M} {code : List (Instr Nat)}
{L : Layout} {base : Nat} {off : Nat → Nat} {g : Facts}
theorem sim_jmp_ok (hs : Rel0 c p s x) (hpc : x.pc = base) {t : Nat}
(hat : RAt code base (lowerInstr L base off g (.jmp t))) :
∃ x', RSteps code x x' ∧ Rel0 c p s x' ∧ x'.pc = off t := by
have hat' : RAt code base [.jmp (off t)] := hat
obtain ⟨f0, _⟩ := hat'
refine ⟨{ x with pc := off t }, RSteps.single (by rw [rstep_of_fetch (by rw [hpc]; exact f0)]; rfl),
hs.congr rfl rfl rfl rfl rfl rfl rfl, rfl⟩
/-- `branch t`: both outcomes. -/
theorem sim_branch_ok (hg : Geom c) (hL : L.dEnd = ofN c.dEnd) (hs : Rel0 c p s x)
(hpc : x.pc = base) {t : Nat} (hat : RAt code base (lowerInstr L base off g (.branch t)))
{cc : W} {d : List W} (hd : s.dstack = cc :: d) :
∃ x', RSteps code x x' ∧ Rel0 c p { s with dstack := d } x' ∧
x'.pc = (if Word.isTrue cc then off t else base + isize g (.branch t : WordDialect.Instr 32)) := by
have hat' : RAt code base (uf L (need g 1) base ++ [.load r0 Reg.r4 0, .addImm Reg.r4 4,
.bnez r0 (off t)]) := hat
obtain ⟨hatuf, hatr⟩ := rat_append.mp hat'
have hufl := uf_length L (need g 1) base
rw [hufl] at hatr
obtain ⟨f0, f1, f2, _⟩ := hatr
have hk : 1 ≤ s.dstack.length := by simp [hd]
obtain ⟨x1, hs1, hr1, hpc1, hm1, _⟩ := uf_pass hg hs hL (by decide) hk hpc hatuf
obtain ⟨x2, hs2, hr2, hpc2, hv2, ho2, _⟩ := ld_step (code := code) hr1 (j := 0) (v := cc)
(by simp [hd]) (rd := r0) (by simp) (disp := 0) (by simp) (fetch_cast f0 (by omega))
obtain ⟨x3, hs3, hr3, hpc3, ho3⟩ := adj_step (code := code) hg hr2 (n := 1) (by simp [hd])
(δ := 4) (by simp) (fetch_cast f1 (by omega))
have hax3 : x3.regs r0 = cc := by rw [ho3 r0 (by decide), hv2]
have e : s.dstack.drop 1 = d := by simp [hd]
rw [e] at hr3
by_cases hc : cc = 0#32
· have hst4 : step code x3 = .next x3.adv := by
rw [rstep_of_fetch (m := x3) (fetch_cast f2 (by omega))]
simp [exec, hax3, hc]
refine ⟨x3.adv, ((hs1.trans hs2).trans hs3).trans (RSteps.single hst4),
hr3.congr rfl rfl rfl rfl rfl rfl rfl, ?_⟩
simp [hc, Word.isTrue, M.adv, hpc3, isize]; omega
· have hst4 : step code x3 = .next { x3 with pc := off t } := by
rw [rstep_of_fetch (m := x3) (fetch_cast f2 (by omega))]
simp [exec, hax3, hc]
refine ⟨{ x3 with pc := off t }, ((hs1.trans hs2).trans hs3).trans (RSteps.single hst4),
hr3.congr rfl rfl rfl rfl rfl rfl rfl, ?_⟩
simp [hc, Word.isTrue]
theorem sim_halt (hs : Rel0 c p s x) (hpc : x.pc = base)
(hat : RAt code base (lowerInstr L base off g .halt)) : RExec code x (.halted x) := by
have hat' : RAt code base [.exitHalt] := hat
obtain ⟨f0, _⟩ := hat'
exact RExec.halt (by rw [rstep_of_fetch (by rw [hpc]; exact f0)]; rfl)
/-- The model's `call` itself: pushes the index of the return instruction onto the return stack
(`sp`). -/
theorem sim_call_core (hg : Geom c) (hs : Rel0 c p s x) (hpc : x.pc = base) {t : Nat}
(hat : RAt code base [.call (off t)])
(hret : base + 1 = offs c.facts p (s.pc + 1)) (hfitR : s.rstack.length + 2 ≤ c.rcap) :
∃ x', RSteps code x x' ∧ Rel0 c p { s with rstack := (s.pc + 1) :: s.rstack } x' ∧
x'.pc = off t := by
obtain ⟨f0, _⟩ := hat
have hcapR := hs.capR
have hrc := hg.rcap_le
have hsp := hg.sp0_lt
have hA1 : c.sp0 - 4 * c.rcap ≤ c.sp0 - 4 * (s.rstack.length + 1) := by omega
have hA2 : c.sp0 - 4 * (s.rstack.length + 1) < c.sp0 := by omega
have hAlt : c.sp0 - 4 * (s.rstack.length + 1) < 2 ^ 32 := by omega
have hvalid := hs.xvalid.2.2.2.1 _ hA1 hA2
have hsub : x.regs sp - 4#32 = ofN (c.sp0 - 4 * (s.rstack.length + 1)) := by
rw [hs.sp]
show ofN _ - ofN 4 = _
rw [ofN_sub (by omega)]
congr 1
obtain ⟨mem', hw⟩ : ∃ m', x.mem.write? (ofN (c.sp0 - 4 * (s.rstack.length + 1)))
(BitVec.ofNat 32 (x.pc + 1)) = some m' := by simp [Memory.write?, hvalid]
have hst : step code x = .next { (x.setReg sp
(ofN (c.sp0 - 4 * (s.rstack.length + 1)))) with mem := mem', pc := off t } := by
rw [rstep_of_fetch (by rw [hpc]; exact f0)]
simp only [exec, hsub, hw]
refine ⟨_, RSteps.single hst, ?_, rfl⟩
have hdE := hg.dEnd_lt
have hcap := hs.capD
refine { r4 := ?_, r5 := ?_, r8 := ?_, r9 := ?_, sp := ?_, stack := ?_, regs := ?_,
mem := ?_, rs := ?_, irvalid := hs.irvalid, xvalid := ?_, capD := hs.capD, capR := ?_,
r6 := by simpa [M.setReg] using hs.r6,
aux := aux_write_other hg.aEnd_lt hs.capA hs.aux hw hAlt
(by rcases hg.dA_K with h | h <;> omega),
capA := hs.capA }
· simpa [M.setReg] using hs.r4
· simpa [M.setReg] using hs.r5
· simpa [M.setReg] using hs.r8
· simpa [M.setReg] using hs.r9
· simp [M.setReg]
· intro i w hi
have hi : s.dstack[i]? = some w := hi
have hik : i < s.dstack.length := by
by_cases hh : i < s.dstack.length
· exact hh
· rw [List.getElem?_eq_none (by omega)] at hi; simp at hi
have hB : c.dEnd - 4 * s.dstack.length + 4 * i < 2 ^ 32 := by omega
have hne : c.sp0 - 4 * (s.rstack.length + 1) ≠ c.dEnd - 4 * s.dstack.length + 4 * i := by
rcases hg.dS_K with h | h <;> omega
show mem'.read? _ = some w
rw [read_write_nat hw hAlt hB]
simp only [hne, ite_false]
exact hs.stack i w hi
· intro r hr
have hrf := hg.rf_lt
have hne : c.sp0 - 4 * (s.rstack.length + 1) ≠ c.rf + 4 * r := by
rcases hg.dF_K with h | h <;> omega
show mem'.read? _ = some _
rw [read_write_nat hw hAlt (by omega)]
simp only [hne, ite_false]
exact hs.regs r hr
· intro a ha
have hmb := hg.mb_lt
have hne : c.sp0 - 4 * (s.rstack.length + 1) ≠ c.mb + 4 * a := by
rcases hg.dM_K with h | h <;> omega
show mem'.read? _ = some _
rw [read_write_nat hw hAlt (by omega)]
simp only [hne, ite_false]
exact hs.mem a ha
· intro i a hi
show mem'.read? _ = some _
simp only [List.length_cons]
cases i with
| zero =>
simp at hi; subst hi
rw [show c.sp0 - 4 * (s.rstack.length + 1) + 4 * 0 = c.sp0 - 4 * (s.rstack.length + 1) by omega,
read_write_nat hw hAlt hAlt]
simp [hpc, hret, ofN]
| succ i =>
simp only [List.getElem?_cons_succ] at hi
have hik : i < s.rstack.length := by
have := (List.getElem?_eq_some_iff.mp hi).1; simpa using this
have hB : c.sp0 - 4 * (s.rstack.length + 1) + 4 * (i + 1) < 2 ^ 32 := by omega
have hne : c.sp0 - 4 * (s.rstack.length + 1) ≠
c.sp0 - 4 * (s.rstack.length + 1) + 4 * (i + 1) := by omega
rw [read_write_nat hw hAlt hB]
simp only [hne, ite_false]
have e : c.sp0 - 4 * (s.rstack.length + 1) + 4 * (i + 1) =
c.sp0 - 4 * s.rstack.length + 4 * i := by omega
rw [e]; exact hs.rs i a hi
· have := Memory.write?_valid hw
show RegionsValid c mem'.valid
rw [this]; exact hs.xvalid
· simp only [List.length_cons]; omega
theorem sim_ret_ok (hg : Geom c) (hs : Rel0 c p s x) (hpc : x.pc = base)
(hat : RAt code base (lowerInstr L base off g .ret)) {a : Nat} {rs : List Nat}
(hr : s.rstack = a :: rs) (hsz : offs c.facts p a < 2 ^ 32) :
∃ x', RSteps code x x' ∧ Rel0 c p { s with rstack := rs } x' ∧ x'.pc = offs c.facts p a := by
have hat' : RAt code base [.bcc .ne sp r9 (base + 2), .exitTrap .returnUnderflow, .ret] := hat
obtain ⟨f0, f1, f3, _⟩ := hat'
have hcapR := hs.capR
have hrc := hg.rcap_le
have hsp := hg.sp0_lt
rw [hr] at hcapR
simp only [List.length_cons] at hcapR
let x1 : M := x
have hrsp : x.regs sp = ofN (c.sp0 - 4 * (rs.length + 1)) := by rw [hs.sp, hr]; simp
have hne : (x.regs sp != x.regs r9) = true := by
rw [hrsp, hs.r9]
have : ofN (c.sp0 - 4 * (rs.length + 1)) ≠ ofN c.sp0 := by
intro e; have := ofN_inj (by omega) hsp e; omega
simpa using this
have hst2 : step code x = .next { x1 with pc := base + 2 } := by
rw [rstep_of_fetch (by rw [hpc]; exact f0)]
simp [exec, Cond.eval, hne, x1]
have hread := hs.rs 0 a (by simp [hr])
rw [hr] at hread
simp only [List.length_cons, Nat.mul_zero, Nat.add_zero] at hread
have hst3 : step code { x1 with pc := base + 2 } = .next { (({ x1 with pc := base + 2 } : M).setReg
sp (ofN (c.sp0 - 4 * rs.length))) with pc := offs c.facts p a } := by
rw [rstep_of_fetch (m := { x1 with pc := base + 2 }) f3]
have hx1r : x1.regs sp = ofN (c.sp0 - 4 * (rs.length + 1)) := hrsp
have hx1m : x1.mem = x.mem := rfl
have hadd : ofN (c.sp0 - 4 * (rs.length + 1)) + 4#32 = ofN (c.sp0 - 4 * rs.length) := by
show ofN _ + ofN 4 = _
rw [ofN_add]; congr 1; omega
have hv : (ofN (offs c.facts p a)).toNat = offs c.facts p a := by
simp [ofN, BitVec.toNat_ofNat, Nat.mod_eq_of_lt hsz]
simp only [exec]
rw [hx1m, hx1r, hread]
simp only [hadd, hv]
refine ⟨_, (RSteps.single hst2).trans (RSteps.single hst3), ?_, rfl⟩
refine { r4 := ?_, r5 := ?_, r8 := ?_, r9 := ?_, sp := ?_, stack := ?_, regs := ?_,
mem := ?_, rs := ?_, irvalid := hs.irvalid, xvalid := ?_, capD := hs.capD, capR := ?_,
r6 := by simpa [M.setReg, x1, M.adv] using hs.r6, aux := hs.aux, capA := hs.capA }
· simpa [M.setReg, x1, M.adv] using hs.r4
· simpa [M.setReg, x1, M.adv] using hs.r5
· simpa [M.setReg, x1, M.adv] using hs.r8
· simpa [M.setReg, x1, M.adv] using hs.r9
· simp [M.setReg]
· exact hs.stack
· exact hs.regs
· exact hs.mem
· intro i a' hi
have h := hs.rs (i + 1) a' (by simpa [hr] using hi)
rw [hr] at h
simp only [List.length_cons] at h
have e : c.sp0 - 4 * (rs.length + 1) + 4 * (i + 1) = c.sp0 - 4 * rs.length + 4 * i := by omega
rw [e] at h
exact h
· exact hs.xvalid
· show rs.length + 1 ≤ c.rcap
omega
theorem sim_ret_trap (hs : Rel0 c p s x) (hpc : x.pc = base)
(hat : RAt code base (lowerInstr L base off g .ret)) (hr : s.rstack = []) :
RExec code x (.trapped .returnUnderflow) := by
have hat' : RAt code base [.bcc .ne sp r9 (base + 2), .exitTrap .returnUnderflow, .ret] := hat
obtain ⟨f0, f1, _⟩ := hat'
have heq : x.regs sp = x.regs r9 := by rw [hs.sp, hs.r9, hr]; simp
have hhold : Cond.eval .ne (x.regs sp) (x.regs r9) = false := by simp [Cond.eval, heq]
exact guard_trap (code := code) (pc := base) (m := x) (t := .returnUnderflow) ⟨f0, f1, trivial⟩
hpc hhold
/-- `call t`: the return-stack guard, then the model's `call`. -/
theorem sim_call_ok (hg : Geom c) (hs : Rel0 c p s x) (hpc : x.pc = base) {t : Nat}
(hLr : L.rGap = ofN (4 * c.rcap - 8)) (hat : RAt code base (lowerInstr L base off g (.call t)))
(hret : base + isize g (.call t : WordDialect.Instr 32) = offs c.facts p (s.pc + 1))
(hfitR : s.rstack.length + 2 ≤ c.rcap) :
∃ x', RSteps code x x' ∧ Rel0 c p { s with rstack := (s.pc + 1) :: s.rstack } x' ∧
x'.pc = off t := by
have hat' : RAt code base (ovfR L base ++ [.call (off t)]) := hat
obtain ⟨hato, hatc⟩ := rat_append.mp hat'
have hl : (ovfR L base).length = 5 := rfl
rw [hl] at hatc
obtain ⟨x1, hs1, hr1, hpc1, _⟩ := ovfR_pass hg hs hLr hfitR hpc hato
obtain ⟨x', hs', hr', hpc'⟩ := sim_call_core hg hr1 hpc1 hatc (by simpa [isize] using hret) hfitR
exact ⟨x', hs1.trans hs', hr', hpc'⟩
theorem sim_call_ovf (hg : Geom c) (hs : Rel0 c p s x) (hpc : x.pc = base) {t : Nat}
(hLr : L.rGap = ofN (4 * c.rcap - 8)) (hat : RAt code base (lowerInstr L base off g (.call t)))
(h : ¬ s.rstack.length + 2 ≤ c.rcap) : RExec code x .overflow := by
have hat' : RAt code base (ovfR L base ++ [.call (off t)]) := hat
exact ovfR_trap hg hs hLr h hpc (rat_append.mp hat').1
end Ctl
end CM0
end WordDialect