Skip to content

Latest commit

 

History

History
1643 lines (1573 loc) · 71.6 KB

notes.org

File metadata and controls

1643 lines (1573 loc) · 71.6 KB

Notes

Create Issue on GitHub about Pattern Tree

Explain blow up, give examples (encode/decode functions for mappings, C backend), possible solutions Case tree data structure (Agda) Ulf Norell Phd

NoConfuseHom

Steven:

I suggest that you implement the manual derivation of EqDec like for RISC-V PMP and skip the NoConfusionHom. In your case you can derive EqDec automatically without NoConfusionHom, but that does not work for e.g. MinimalCaps. I have also adapted the MinimalCaps code to add the manual derivation of EqDec without NoConfusionHom: https://github.com/katamaran-project/katamaran/commit/fa11745030f3fd9ab5d4b050989c45b08b1d0a47

Have Sail inline functions

Check monomorphization abilities

Variant with unit field type should have 0 fields

Bitvectors

Bit type in MuSail?

Coq

(* Denotation of muSail types, TypeDecl.v *)
Fixpoint Val (σ : Ty) : Set :=
  match σ with
  | int => Z
  | bool => Datatypes.bool
  | string => String.string
  | list σ' => Datatypes.list (Val σ')
  | prod σ1 σ2 => Val σ1 * Val σ2
  | sum σ1 σ2 => Val σ1 + Val σ2
  | unit => Datatypes.unit
  | enum E => enumt E
  | bvec n => bv n
  | tuple σs => EnvRec Val σs
  | union U => uniont U
  | record R => recordt R
  end%type.


(* Bitvector value, BitvectorBase.v *)
Record bv (n : nat) : Set :=
  mk { bin : N; _ : Is_true (is_wf n bin) }.


(* Bitvector operations *)
Notation "e1 +ᵇ e2" := (exp_binop bop.bvadd e1 e2) : exp_scope.
Notation "e1 -ᵇ e2" := (exp_binop bop.bvsub e1 e2) : exp_scope.
Notation "e1 *ᵇ e2" := (exp_binop bop.bvmul e1 e2) : exp_scope.

Notation "[ 'bits' x ]" := (of_bitstring x%bits)
    (format "[ 'bits'  x ]") : bv_scope.
Notation "[ 'bits' ]" := (@of_bitstring 0 bitstring.bN)
    (format "[ 'bits' ]") : bv_scope.
Notation "[ 'bits' [ n ] x ]" := (@of_bitstring n x%bits)
    (only parsing) : bv_scope.
Notation "[ 'bits' [ 0 ] ]" := (@of_bitstring 0 bitstring.bN)
    (only parsing) : bv_scope.

Notation "[ 'bv' x ]" := (mk x%xN I) (format "[ 'bv'  x ]") : bv_scope.
Notation "[ 'bv' [ n ] x ]" := (@mk n x%xN I) (only parsing) : bv_scope.


  | shiftr {m n}      : BinOp (bvec m) (bvec n) (bvec m)
  | shiftl {m n}      : BinOp (bvec m) (bvec n) (bvec m)
  | bvadd {n}         : BinOp (bvec n) (bvec n) (bvec n)
  | bvsub {n}         : BinOp (bvec n) (bvec n) (bvec n)
  | bvmul {n}         : BinOp (bvec n) (bvec n) (bvec n)
  | bvand {n}         : BinOp (bvec n) (bvec n) (bvec n)
  | bvor {n}          : BinOp (bvec n) (bvec n) (bvec n)
  | bvxor {n}         : BinOp (bvec n) (bvec n) (bvec n)
  | bvapp {m n}       : BinOp (bvec m) (bvec n) (bvec (m + n))


(* works *)
stm_exp (exp_val (ty.bvec 8) ([bv 0]))

Triples in records

Base Module

Eqdec

Folds

Record folds

Definition record_fold (R : recordi) : NamedEnv Val (record_field_type R) -> recordt R :=
  match R with
  | capability =>

      fun fields =>
      MkCap
        fields.[??"cap_permission"]
        fields.[??"cap_begin"]
        fields.[??"cap_end"]
        fields.[??"cap_cursor"]
  end%exp.
record_fold =
fun R : recordi =>
match R as R0 return (forall _ : NamedEnv Val (record_field_type R0), recordt R0) with
| capability =>
    fun fields : NamedEnv Val (record_field_type capability) =>
    {|
      cap_permission := env.lookup fields {| ctx.in_at := 3; ctx.in_valid := eq_refl |};
      cap_begin := env.lookup fields {| ctx.in_at := 2; ctx.in_valid := eq_refl |};
      cap_end := env.lookup fields {| ctx.in_at := 1; ctx.in_valid := eq_refl |};
      cap_cursor := env.lookup fields {| ctx.in_at := 0; ctx.in_valid := eq_refl |}
    |}
end

Record unfolds

Definition record_unfold (R : recordi) : recordt R -> NamedEnv Val (record_field_type R) :=
match R  with
| capability =>
  fun c=>
    env.nil
      ► ("cap_permission" ∷ ty.perm ↦ cap_permission c)
      ► ("cap_begin"      ∷ ty.addr ↦ cap_begin c)
      ► ("cap_end"        ∷ ty.addr ↦ cap_end c)
      ► ("cap_cursor"     ∷ ty.addr ↦ cap_cursor c)
end%env.
record_unfold =
λ R : recordi,
  match R as R0 return (recordt R0 → NamedEnv Val (record_field_type R0)) with
  | capability =>
      λ c : recordt capability, [env].["cap_permission"∷ty.perm ↦ cap_permission c]
        .["cap_begin"∷ty.addr ↦ cap_begin c].["cap_end"∷ty.addr ↦ cap_end c].["cap_cursor"∷ty.addr ↦ 
        cap_cursor c]
  end
     : ∀ R : recordi, recordt R → NamedEnv Val (record_field_type R)

record_field_type

typedefkit

Canonicals

Use monads in Base Module

Matching statements

Investigate stm_match_union_alt

union clause ast = JALR_CAP      : (dst, src)
union c lause ast = CJALR         : (dst, src, imm)
union clause ast = CJAL	         : (dst, imm_ext)
union clause ast = BNE           : (src, src, imm)
union clause ast = LD            : (dst, src, imm)
union clause ast = SD            : (src, src, imm)
union clause ast = ADDI          : (dst, src, imm)
union clause ast = ADD           : (dst, src, src)
union clause ast = SUB           : (dst, src, src)
union clause ast = SLT           : (dst, src, src)
union clause ast = SLTI          : (dst, src, imm)
union clause ast = SLTIU         : (dst, src, imm)
union clause ast = SLTU          : (dst, src, src)
union clause ast = CMOVE         : (dst, src)
union clause ast = CINCOFFSET    : (dst, src, src)
union clause ast = CANDPERM      : (dst, src, src)
union clause ast = CSETBOUNDS    : (dst, src, src)
union clause ast = CSETBOUNDSIMM : (dst, src, imm)
union clause ast = CGETTAG       : (dst, src)
union clause ast = CGETPERM      : (dst, src)
union clause ast = CGETBASE      : (dst, src)
union clause ast = CGETLEN       : (dst, src)
union clause ast = CGETADDR      : (dst, src)
union clause ast = FAIL          : unit
union clause ast = RET           : unit

function clause execute(JALR_CAP(cd, cs)) =
  execute(CJALR(cd, cs, sail_zeros(imm_size)))

function clause execute(CJALR(cd, cs, imm)) = {
  let npc = nextPC();
  writeReg(cd) = Cap(npc);
  let c = readRegCap(cs);
  if not(canIncrCursor(c, imm))
  then throw(CapabilityCursorCannotBeModified())
  else {
    let imm = sail_zero_extend(imm, integer_size);  // TODO Why sail_zero_extend and not sail_sign_extend?
    let c' = updatePCPerm({c with cap_cursor = c.cap_cursor + imm}); // TODO shouldn't cursor[0] should be set to 0?
    PC = c';
    true
  }
}

function clause execute(CJAL(cd, imm)) = {
  let npc = nextPC();
  writeReg(cd) = Cap(npc);
  addPC(sail_shiftleft(sail_zero_extend(imm, integer_size), 1));
  true
}
Definition fun_exec_instr : Stm [i :: ty.instr] ty.bool :=
stm_match_union_alt
  instruction (exp_var i)
  (fun K =>
     match K with
     | kjalr_cap      => MkAlt (pat_pair "cd" "cs")
                               (call exec_jalr_cap (exp_var "cd") (exp_var "cs"))%exp
     | kcjalr         => MkAlt (pat_tuple ("cd" , "cs" , "imm"))
                               (call exec_cjalr (exp_var "cd") (exp_var "cs") (exp_var "imm"))%exp
     | kcjal          => MkAlt (pat_pair "cd" "imm")
                               (call exec_cjal (exp_var "cd") (exp_var "imm"))%exp
     | kbne           => MkAlt (pat_tuple ("rs1" , "rs2" , "imm"))
                               (call exec_bne (exp_var "rs1") (exp_var "rs2") (exp_var "imm"))%exp
     | kcmove         => MkAlt (pat_pair "cd" "cs")
                               (call exec_cmove (exp_var "cd") (exp_var "cs"))%exp
     | kld            => MkAlt (pat_tuple ("cd" , "cs" , "imm"))
                               (call exec_ld (exp_var "cd") (exp_var "cs") (exp_var "imm"))%exp
     | ksd            => MkAlt (pat_tuple ("rs1" , "rs2" , "imm"))
                               (call exec_sd (exp_var "rs1") (exp_var "rs2") (exp_var "imm"))%exp
     | kcincoffset    => MkAlt (pat_tuple ("cd" , "cs" , "rs"))
                               (call exec_cincoffset (exp_var "cd") (exp_var "cs") (exp_var "rs"))%exp
     | kcandperm      => MkAlt (pat_tuple ("cd" , "cs" , "rs"))
                               (call exec_candperm (exp_var "cd") (exp_var "cs") (exp_var "rs"))%exp
     | kcsetbounds    => MkAlt (pat_tuple ("cd" , "cs" , "rs"))
                               (call exec_csetbounds (exp_var "cd") (exp_var "cs") (exp_var "rs"))%exp
     | kcsetboundsimm => MkAlt (pat_tuple ("cd" , "cs" , "imm"))
                               (call exec_csetboundsimm (exp_var "cd") (exp_var "cs") (exp_var "imm"))%exp
     | kaddi          => MkAlt (pat_tuple ("rd" , "rs" , "imm"))
                               (call exec_addi (exp_var "rd") (exp_var "rs") (exp_var "imm"))%exp
     | kadd           => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
                               (call exec_add (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
     | ksub           => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
                               (call exec_sub (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
     | kslt           => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
                               (call exec_slt (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
     | kslti          => MkAlt (pat_tuple ("rd" , "rs" , "imm"))
                               (call exec_slti (exp_var "rd") (exp_var "rs") (exp_var "imm"))%exp
     | ksltu          => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
                               (call exec_sltu (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
     | ksltiu         => MkAlt (pat_tuple ("rd" , "rs" , "imm"))
                               (call exec_sltiu (exp_var "rd") (exp_var "rs") (exp_var "imm"))%exp
     | kcgettag       => MkAlt (pat_pair "rd" "cs")
                               (call exec_cgettag (exp_var "rd") (exp_var "cs"))%exp
     | kcgetperm      => MkAlt (pat_pair "rd" "cs")
                               (call exec_cgetperm (exp_var "rd") (exp_var "cs"))%exp
     | kcgetbase      => MkAlt (pat_pair "rd" "cs")
                               (call exec_cgetbase (exp_var "rd") (exp_var "cs"))%exp
     | kcgetlen       => MkAlt (pat_pair "rd" "cs")
                               (call exec_cgetlen (exp_var "rd") (exp_var "cs"))%exp
     | kcgetaddr      => MkAlt (pat_pair "rd" "cs")
                               (call exec_cgetaddr (exp_var "rd") (exp_var "cs"))%exp
     | kfail          => MkAlt pat_unit
                               (call exec_fail)%exp
     | kret           => MkAlt pat_unit
                               (call exec_ret)%exp
     end).

match |> notation (enums, unions/variants)

For the pattern matching on unions I suggest using https://github.com/katamaran-project/katamaran/blob/6b50d42d5fa4027be887fbd39ccadd3acd57b688/theories/Syntax/Statements.v#L181-L188 For a union type U and scrutinee s it takes a list of alternatives altsand a well-formedness (exhaustiveness) proof alts_wf.

(* Statements.v *)

Definition stm_match_union_alt_list {Γ τ} U (s : Stm Γ (ty.union U))
  (alts : UnionAlts U Γ τ) (alts_wf : UnionAltsWf alts) : Stm Γ τ :=
  stm_match_union_alt U s
    (fun K =>
       match findUnionAlt K alts as o return findUnionAlt K alts = o -> _ with
       | Some alt => fun _   => alt
       | None     => fun Heq => False_rect _ (union_alts_wf' alts alts_wf Heq)
       end eq_refl).

https://github.com/katamaran-project/katamaran|katamaran-project/katamarankatamaran-project/katamaran | Added by GitHub 1:42 For the well-formedness you should just pass Logic.I , i.e. the constructor of True which forces Coq’s typechecker to decide well-formedness. See the notation as a reference https://github.com/katamaran-project/katamaran/blob/6b50d42d5fa4027be887fbd39ccadd3acd57b688/theories/Syntax/Statements.v#L562-L564

(* Statements.v *)

Notation "'match:' e 'in' 'union' U 'with' | x | y | .. | z 'end'" :=
  (stm_match_union_alt_list U e (cons x%alt (cons y%alt .. (cons z%alt nil) ..)) Logic.I)
    (format "'[hv' 'match:'  e  'in'  'union'  U  'with'  '/' | x  '/' | y  '/' | ..  '/' | z  '/' 'end' ']'") : exp_scope.
Notation "'match:' e 'in' 'union' U 'with' | x | y | .. | z 'end'" :=
  (stm_match_union_alt_list U e (cons x%alt (cons y%alt .. (cons z%alt nil) ..)) Logic.I)
  (format "'[hv' 'match:'  e  'in'  'union'  U  'with'  '/' | x  '/' | y  '/' | ..  '/' | z  '/' 'end' ']'") : exp_scope.

Notation "'>' K pat => rhs" := (existT K (MkAlt pat rhs%exp))
  (K global, at level 200, pat at level 9, format ">  K  pat  =>  rhs") : alt_scope.

match: acc in union access_type with
  |> KRead pat_unit      => stm_exp (Some E_Load_Access_Fault)
  |> KWrite pat_unit     => stm_exp (Some E_SAMO_Access_Fault)
  |> KReadWrite pat_unit => stm_exp (Some E_SAMO_Access_Fault)
  |> KExecute pat_unit   => stm_exp (Some E_Fetch_Access_Fault)
end

Definition fun_foo : Stm [ "u"  ∷  ty.union Umyunion ] (ty.int) :=
  stm_let
    "жmatched1"
    (ty.union Umyunion)
    (stm_exp (exp_var "u"))
    (stm_match_union_alt_list
       Umyunion
       (stm_exp (exp_var "жmatched1"))
       [ existT Kpush (MkAlt pat_unit (stm_exp (exp_int 1%Z))) ]
       Logic.I).

enum_denote should contain regname

Unions/Variants

Notation "'Read'" := (exp_union access_type KRead (exp_val ty.unit tt)) : exp_scope.
Notation "'Write'" := (exp_union access_type KWrite (exp_val ty.unit tt)) : exp_scope.
Notation "'ReadWrite'" := (exp_union access_type KReadWrite (exp_val ty.unit tt)) : exp_scope.
Notation "'Execute'" := (exp_union access_type KExecute (exp_val ty.unit tt)) : exp_scope.

Notation "'E_Fetch_Access_Fault'" := (exp_union exception_type KE_Fetch_Access_Fault (exp_val ty.unit tt)) : exp_scope.
Notation "'E_Load_Access_Fault'" := (exp_union exception_type KE_Load_Access_Fault (exp_val ty.unit tt)) : exp_scope.
Notation "'E_SAMO_Access_Fault'" := (exp_union exception_type KE_SAMO_Access_Fault (exp_val ty.unit tt)) : exp_scope.
Notation "'E_U_EnvCall'" := (exp_union exception_type KE_U_EnvCall (exp_val ty.unit tt)) : exp_scope.
Notation "'E_M_EnvCall'" := (exp_union exception_type KE_M_EnvCall (exp_val ty.unit tt)) : exp_scope.
Notation "'E_Illegal_Instr'" := (exp_union exception_type KE_Illegal_Instr (exp_val ty.unit tt)) : exp_scope.

Notation "'None'" := (exp_inr (exp_val ty.unit tt)) : exp_scope.
Notation "'Some' va" := (exp_inl va) (at level 10, va at next level) : exp_scope.

Notation "'MemValue' bs memv" := (exp_union (memory_op_result bs) KMemValue memv) (at level 10, memv at next level) : exp_scope.
Notation "'MemException' bs meme" := (exp_union (memory_op_result bs) KMemException meme) (at level 10, meme at next level) : exp_scope.

Notation "'F_Base' memv" := (exp_union fetch_result KF_Base memv) (at level 10, memv at next level) : exp_scope.
Notation "'F_Error' meme memv" := (exp_union fetch_result KF_Error (exp_binop bop.pair meme memv)) (at level 10, meme at next level, memv at next level) : exp_scope.

Notation "'CTL_TRAP' exc" := (exp_union ctl_result KCTL_TRAP exc) (at level 10, exc at next level) : exp_scope.
Notation "'CTL_MRET'" := (exp_union ctl_result KCTL_MRET (exp_val ty.unit tt)) : exp_scope.

stm_exp (exp_union Uinstruction Kpop (exp_tuple [(exp_int 2%Z); (exp_int 4%Z); (exp_int 8%Z)])).

Notations

Notation "e .[?? x ]" := (@lookup _ _ _ e (x∷_) _)
  (at level 2, x at level 200, only parsing).

Types

enum Permission = O | R | RW | E

struct Capability = {
  cap_permission: Permission,
  cap_begin:      address,
  cap_end:        address,
  cap_cursor:     address,
}

union word = {
  Cap : Capability,
  Num : integer
}

Files

Base.v

+ From Coq Require Import
+      Classes.EquivDec
+      Strings.String.
+ From stdpp Require
+      finite.
+ From Equations Require Import
+      Equations.
+ Require Import Katamaran.Base.
+ 
+ (*** TYPES ***)
+ 
+ Inductive RegName : Set :=
+   R0 | R1 | R2 | R3.
+ 
+ Definition Dst : Set := RegName.
+ Definition Src : Set := RegName.
+ Definition Imm : Set := Z.
+ 
+ Inductive Instruction : Set :=
+ | jalr_cap      (cd  : Dst) (cs  : Src)
+ | cjalr         (cd  : Dst) (cs  : Src) (imm : Imm)
+ | cjal          (cd  : Dst) (imm : Imm)
+ | bne           (rs1 : Src) (rs2 : Src) (imm : Imm)
+ | ld            (cd  : Dst) (cs  : Src) (imm : Imm)
+ | sd            (rs1 : Src) (rs2 : Src) (imm : Imm)
+ | addi          (rd  : Dst) (rs  : Src) (imm : Imm)
+ | add           (rd  : Dst) (rs1 : Src) (rs2 : Src)
+ | sub           (rd  : Dst) (rs1 : Src) (rs2 : Src)
+ | slt           (rd  : Dst) (rs1 : Src) (rs2 : Src)
+ | slti          (rd  : Dst) (rs  : Src) (imm : Imm)
+ | sltu          (rd  : Dst) (rs1 : Src) (rs2 : Src)
+ | sltiu         (rd  : Dst) (rs  : Src) (imm : Imm)
+ | cmove         (cd  : Dst) (cs  : Src)
+ | cincoffset    (cd  : Dst) (cs  : Src) (rs : Src)
+ | candperm      (cd  : Dst) (cs  : Src) (rs : Src)
+ | csetbounds    (cd  : Dst) (cs  : Src) (rs : Src)
+ | csetboundsimm (cd  : Dst) (cs  : Src) (imm : Imm)
+ | cgettag       (rd  : Dst) (cd  : Src)
+ | cgetperm      (rd  : Dst) (cs  : Src)
+ | cgetbase      (rd  : Dst) (cs  : Src)
+ | cgetlen       (rd  : Dst) (cs  : Src)
+ | cgetaddr      (rd  : Dst) (cs  : Src)
+ | fail
+ | ret.
+ 
+ Inductive InstructionConstructor : Set :=
+ | kjalr_cap
+ | kcjalr
+ | kcjal
+ | kbne
+ | kcmove
+ | kld
+ | ksd
+ | kaddi
+ | kadd
+ | ksub
+ | kslt
+ | kslti
+ | ksltu
+ | ksltiu
+ | kcincoffset
+ | kcandperm
+ | kcsetbounds
+ | kcsetboundsimm
+ | kcgettag
+ | kcgetperm
+ | kcgetbase
+ | kcgetlen
+ | kcgetaddr
+ | kfail
+ | kret.
+ 
+ Inductive Permission : Set :=
+   O | R | RW | E.
+ 
+ Definition Addr : Set := Z.
+ 
+ Record Capability : Set :=
+   MkCap
+     { cap_permission : Permission;
+       cap_begin      : Addr;
+       cap_end        : Addr;
+       cap_cursor     : Addr;
+     }.
+ 
+ (** Enums **)
+ Inductive Enums : Set :=
+ | permission
+ | regname.
+ 
+ (** Unions **)
+ Inductive Unions : Set :=
+ | instruction.
+ 
+ (** Records **)
+ Inductive Records : Set :=
+ | capability.
+ 
+ Section TransparentObligations.
+   Local Set Transparent Obligations.
+ 
+   Derive NoConfusion for Capability.
+   Derive NoConfusion for Permission.
+   Derive NoConfusion for RegName.
+   Derive NoConfusion for Enums.
-   Derive NoConfusion for Unions.
-   Derive NoConfusion for Records.
-   Derive NoConfusion for Instruction.
-   Derive NoConfusion for InstructionConstructor.
+ 
+ End TransparentObligations.

+ Derive EqDec for Permission.
- Definition is_perm := @equiv_decb _ _ _ Permission_eqdec.
- Lemma is_perm_iff : forall p p',
-     is_perm p p' = true <-> p = p'.
- Proof.
-   unfold is_perm.
-   intros; split.
-   - destruct p, p'; cbn; intros ?; auto; try discriminate.
-   - intros; subst; destruct p'; auto.
- Qed.
- 
+ Derive EqDec for Capability.
+ Derive EqDec for RegName.
+ 
+ Derive EqDec for Enums.
+ Derive EqDec for Unions.
+ Derive EqDec for Records.
+ Derive EqDec for Instruction.
+ Derive EqDec for InstructionConstructor.
+ 
+ Section Finite.
+ 
+   Import stdpp.finite.
+ 
+   Local Obligation Tactic :=
+     finite_from_eqdec.
+ 
+   #[export,program] Instance Permission_finite : Finite Permission :=
+     {| enum := [O;R;RW;E] |}.
+ 
+   #[export,program] Instance RegName_finite : Finite RegName :=
+     {| enum := [R0;R1;R2;R3] |}.
+ 
+   #[export,program] Instance InstructionConstructor_finite :
+     Finite InstructionConstructor :=
+     {| enum := [kjalr_cap;kcjalr;kcjal;kbne;kcmove;kld;ksd;kcincoffset;kcandperm;kcsetbounds;kcsetboundsimm;kcgettag;kaddi;kadd;ksub;kslt;kslti;ksltu;ksltiu;kcgetperm;kcgetbase;kcgetlen;kcgetaddr;kfail;kret] |}.
+ 
+ End Finite.
+ 
+ Module Export MinCapsBase <: Base.
+   Import ctx.notations.
+   Import ctx.resolution.
+   Import env.notations.
+   Import stdpp.finite.
+ 
+   Local Open Scope string_scope.
+ 
+   #[export] Instance typedeclkit : TypeDeclKit :=
+     {| enumi := Enums;
+        unioni := Unions;
+        recordi := Records;
+    |}.
+ 
-   Notation "ty.dst" := (ty.enum regname).
-   Notation "ty.src" := (ty.enum regname).
-   Notation "ty.cap" := (ty.record capability).
-   Notation "ty.word" := (ty.sum ty.int ty.cap).
-   Notation "ty.memval" := (ty.word).
-   Notation "ty.addr" := (ty.int).
-   Notation "ty.perm" := (ty.enum permission).
-   Notation "ty.instr" := (ty.union instruction).
- 
+   Definition enum_denote (e : Enums) : Set :=
+     match e with
+    | permission => Permission
+    | regname    => RegName
+     end.
+ 
+   Definition union_denote (U : Unions) : Set :=
+     match U with
+    | instruction => Instruction
+     end.
+ 
+   Definition record_denote (R : Records) : Set :=
+     match R with
+    | capability => Capability
+     end.
+ 
+   #[export] Instance typedenotekit : TypeDenoteKit typedeclkit :=
+     {| enumt := enum_denote;
+        uniont := union_denote;
+        recordt := record_denote;
+    |}.
+ 
+   Definition union_constructor (U : Unions) : Set :=
+     match U with
+    | instruction => InstructionConstructor
+     end.
+ 
+   Definition union_constructor_type (U : Unions) : union_constructor U -> Ty :=
+     match U with
+    | instruction => fun K =>
+       match K with
+      | kjalr_cap      => ty.prod ty.dst ty.src
+      | kcjalr         => ty.tuple [ty.dst; ty.src; ty.int]
+      | kcjal          => ty.prod ty.dst ty.int
+      | kbne           => ty.tuple [ty.src; ty.src; ty.int]
+      | kld            => ty.tuple [ty.dst; ty.src; ty.int]
+      | ksd            => ty.tuple [ty.src; ty.src; ty.int]
+      | kaddi          => ty.tuple [ty.dst; ty.src; ty.int]
+      | kadd           => ty.tuple [ty.dst; ty.src; ty.src]
+      | ksub           => ty.tuple [ty.dst; ty.src; ty.src]
+      | kslt           => ty.tuple [ty.dst; ty.src; ty.src]
+      | kslti          => ty.tuple [ty.dst; ty.src; ty.int]
+      | ksltu          => ty.tuple [ty.dst; ty.src; ty.src]
+      | ksltiu         => ty.tuple [ty.dst; ty.src; ty.int]
+      | kcmove         => ty.prod ty.dst ty.src
+      | kcincoffset    => ty.tuple [ty.dst; ty.src; ty.src]
+      | kcandperm      => ty.tuple [ty.dst; ty.src; ty.src]
+      | kcsetbounds    => ty.tuple [ty.dst; ty.src; ty.src]
+      | kcsetboundsimm => ty.tuple [ty.dst; ty.src; ty.int]
+      | kcgetperm      => ty.prod ty.dst ty.src
+      | kcgetbase      => ty.prod ty.dst ty.src
+      | kcgetlen       => ty.prod ty.dst ty.src
+      | kcgetaddr      => ty.prod ty.dst ty.src
+      | kfail          => ty.unit
+      | kret           => ty.unit
+      | kcgettag       => ty.prod ty.dst ty.src
+       end
+     end.
- 
-   #[export] Instance eqdec_enum_denote E : EqDec (enum_denote E) :=
-     ltac:(destruct E; auto with typeclass_instances).
-   #[export] Instance finite_enum_denote E : finite.Finite (enum_denote E) :=
-     ltac:(destruct E; auto with typeclass_instances).
-   #[export] Instance eqdec_union_denote U : EqDec (union_denote U) :=
-     ltac:(destruct U; cbn; auto with typeclass_instances).
-   #[export] Instance eqdec_union_constructor U : EqDec (union_constructor U) :=
-     ltac:(destruct U; cbn; auto with typeclass_instances).
-   #[export] Instance finite_union_constructor U : finite.Finite (union_constructor U) :=
-     ltac:(destruct U; cbn; auto with typeclass_instances).
-   #[export] Instance eqdec_record_denote R : EqDec (record_denote R) :=
-     ltac:(destruct R; auto with typeclass_instances).
- 
-   Definition union_fold (U : unioni) : { K & Val (union_constructor_type U K) } -> uniont U :=
-     match U with
-    | instruction => fun Kv =>
-       match Kv with
-      | existT kjalr_cap      (cd , cs)              => jalr_cap      cd  cs
-      | existT kcjalr         (tt , cd , cs , imm)   => cjalr         cd  cs  imm
-      | existT kcjal          (cd , imm)             => cjal          cd  imm
-      | existT kbne           (tt , rs1 , rs2 , imm) => bne           rs1 rs2 imm
-      | existT kld            (tt , cd , cs , imm)   => ld            cd  cs  imm
-      | existT ksd            (tt , rs1 , rs2, imm)  => sd            rs1 rs2 imm
-      | existT kaddi          (tt , rd , rs , imm)   => addi          rd  rs  imm
-      | existT kadd           (tt , rd , rs1 , rs2)  => add           rd  rs1 rs2
-      | existT ksub           (tt , rd , rs1 , rs2)  => sub           rd  rs1 rs2
-      | existT kslt           (tt , rd , rs1 , rs2)  => slt           rd  rs1 rs2
-      | existT kslti          (tt , rd , rs , imm)   => slti          rd  rs  imm
-      | existT ksltu          (tt , rd , rs1 , rs2)  => sltu          rd  rs1 rs2
-      | existT ksltiu         (tt , rd , rs , imm)   => sltiu         rd  rs  imm
-      | existT kcmove         (cd , cs)              => cmove         cd  cs
-      | existT kcincoffset    (tt , cd , cs , rs)    => cincoffset    cd  cs  rs
-      | existT kcandperm      (tt , cd , cs , rs)    => candperm      cd  cs  rs
-      | existT kcsetbounds    (tt , cd , cs , rs)    => csetbounds    cd  cs  rs
-      | existT kcsetboundsimm (tt , cd , cs , imm)   => csetboundsimm cd  cs  imm
-      | existT kcgettag       (rd , cs)              => cgettag       rd  cs
-      | existT kcgetperm      (rd , cs)              => cgetperm      rd  cs
-      | existT kcgetbase      (rd , cs)              => cgetbase      rd  cs
-      | existT kcgetlen       (rd , cs)              => cgetlen       rd  cs
-      | existT kcgetaddr      (rd , cs)              => cgetaddr      rd  cs
-      | existT kfail          tt                     => fail
-      | existT kret           tt                     => ret
-       end
-     end.
- 
-   Definition union_unfold (U : unioni) : uniont U -> { K & Val (union_constructor_type U K) } :=
-     match U with
-    | instruction => fun Kv =>
-       match Kv with
-      | jalr_cap      cd  cs      => existT kjalr_cap      (cd , cs)
-      | cjalr         cd  cs  imm => existT kcjalr         (tt , cd , cs , imm)
-      | cjal          cd  imm     => existT kcjal          (cd , imm)
-      | bne           rs1 rs2 imm => existT kbne           (tt , rs1 , rs2 , imm)
-      | ld            cd  cs  imm => existT kld            (tt , cd , cs , imm)
-      | sd            rs1 rs2 imm => existT ksd            (tt , rs1 , rs2 , imm)
-      | addi          rd  rs  imm => existT kaddi          (tt , rd , rs , imm)
-      | add           rd  rs1 rs2 => existT kadd           (tt , rd , rs1 , rs2)
-      | sub           rd  rs1 rs2 => existT ksub           (tt , rd , rs1 , rs2)
-      | slt           rd  rs1 rs2 => existT kslt           (tt , rd , rs1 , rs2)
-      | slti          rd  rs  imm => existT kslti          (tt , rd , rs , imm)
-      | sltu          rd  rs1 rs2 => existT ksltu          (tt , rd , rs1 , rs2)
-      | sltiu         rd  rs  imm => existT ksltiu         (tt , rd , rs , imm)
-      | cmove         cd  cs      => existT kcmove         (cd , cs)
-      | cincoffset    cd  cs  rs  => existT kcincoffset    (tt , cd , cs , rs)
-      | candperm      cd  cs  rs  => existT kcandperm      (tt , cd , cs , rs)
-      | csetbounds    cd  cs  rs  => existT kcsetbounds    (tt, cd , cs , rs)
-      | csetboundsimm cd  cs  imm => existT kcsetboundsimm (tt, cd , cs , imm)
-      | cgettag       rd  cs      => existT kcgettag       (rd , cs)
-      | cgetperm      rd  cs      => existT kcgetperm      (rd , cs)
-      | cgetbase      rd  cs      => existT kcgetbase      (rd , cs)
-      | cgetlen       rd  cs      => existT kcgetlen       (rd , cs)
-      | cgetaddr      rd  cs      => existT kcgetaddr      (rd , cs)
-      | fail                      => existT kfail          tt
-      | ret                       => existT kret           tt
-       end
-     end.
- 
-   Definition record_field_type (R : recordi) : NCtx string Ty :=
-     match R with
-    | capability => [ "cap_permission" ∷ ty.perm;
-                       "cap_begin"      ∷ ty.addr;
-                       "cap_end"        ∷ ty.addr;
-                       "cap_cursor"     ∷ ty.addr
-                     ]
-     end.
- 
-   Definition record_fold (R : recordi) : NamedEnv Val (record_field_type R) -> recordt R :=
-     match R with
-    | capability =>
-       fun fields =>
-         MkCap
-           fields.[??"cap_permission"]
-           fields.[??"cap_begin"]
-           fields.[??"cap_end"]
-           fields.[??"cap_cursor"]
-     end%exp.
- 
-   Definition record_unfold (R : recordi) : recordt R -> NamedEnv Val (record_field_type R) :=
-     match R  with
-    | capability =>
-       fun c=>
-         env.nil
-           ► ("cap_permission" ∷ ty.perm ↦ cap_permission c)
-           ► ("cap_begin"      ∷ ty.addr ↦ cap_begin c)
-           ► ("cap_end"        ∷ ty.addr ↦ cap_end c)
-           ► ("cap_cursor"     ∷ ty.addr ↦ cap_cursor c)
-     end%env.
- 
-   #[export,refine] Instance typedefkit : TypeDefKit typedenotekit :=
-     {| unionk           := union_constructor;
-        unionk_ty        := union_constructor_type;
-        recordf          := string;
-        recordf_ty       := record_field_type;
-        unionv_fold      := union_fold;
-        unionv_unfold    := union_unfold;
-        recordv_fold     := record_fold;
-        recordv_unfold   := record_unfold;
-    |}.
-   Proof.
-     - abstract (now intros [] []).
-     - abstract (intros [] [[] x]; cbn in x;
-                 repeat
-                   match goal with
-                  | x: unit     |- _ => destruct x
-                  | x: prod _ _ |- _ => destruct x
-                   end; auto).
-     - abstract (now intros [] []).
-     - abstract (intros []; now apply env.Forall_forall).
-   Defined.
- 
-   Canonical typedeclkit.
-   Canonical typedenotekit.
-   Canonical typedefkit.
- 
-   #[export] Instance varkit : VarKit := DefaultVarKit.
- 
+   Section RegDeclKit.
+ 
+     Inductive Reg : Ty -> Set :=
+    | pc   : Reg ty.cap
+    | reg1 : Reg ty.word
+    | reg2 : Reg ty.word
+    | reg3 : Reg ty.word.
+ 
+     Section TransparentObligations.
+       Local Set Transparent Obligations.
+       Derive Signature NoConfusion NoConfusionHom EqDec for Reg.
+     End TransparentObligations.
+ 
+     Definition 𝑹𝑬𝑮 : Ty -> Set := Reg.
+     #[export] Instance 𝑹𝑬𝑮_eq_dec : EqDec (sigT Reg) :=
+       sigma_eqdec _ _.
+ 
+     Local Obligation Tactic :=
+       finite_from_eqdec.
+ 
+     #[export,program] Instance 𝑹𝑬𝑮_finite : Finite (sigT Reg) :=
+       {| enum := [ existT _ pc; existT _ reg1; existT _ reg2; existT _ reg3 ] |}.
+ 
+   End RegDeclKit.
- 
-   Section MemoryModel.
-     Definition Memory := Addr -> (Z + Capability).
-   End MemoryModel.
- 
-   Include BaseMixin.
- 
- End MinCapsBase.

Machine.v

+ From Coq Require Import
+      Strings.String
+      ZArith.ZArith.
+ From Equations Require Import
+      Equations.
+ From Katamaran Require Import
+      Program
+      Semantics.Registers
+      Syntax.BinOps.
+ From Katamaran Require Export
+      MinimalCaps.Base.
+ 
+ From stdpp Require Import finite decidable.
+ 
+ Set Implicit Arguments.
+ Import ctx.notations.
+ Import ctx.resolution.
+ Import env.notations.
+ Open Scope string_scope.
+ 
+ (*** Program ***)
+ 
+ Import MinCapsBase.
+ Module Export MinCapsProgram <: Program MinCapsBase.
+ 
+ Section FunDeclKit.
+   Inductive Fun : PCtx -> Ty -> Set :=
+   | read_reg           : Fun ["rs" :: ty.enum regname] ty.word
+   | read_reg_cap       : Fun ["cs" :: ty.enum regname] ty.cap
+   | read_reg_num       : Fun ["rs" :: ty.enum regname] ty.int
+   | write_reg          : Fun ["rd" :: ty.enum regname; "w" :: ty.word] ty.unit
+   | next_pc            : Fun [] ty.cap
+   | update_pc          : Fun [] ty.unit
+   | update_pc_perm     : Fun ["c" :: ty.cap] ty.cap
+   | is_correct_pc      : Fun ["c" :: ty.cap] ty.bool
+   | is_perm            : Fun ["p" :: ty.perm; "p'" :: ty.perm] ty.bool
+   | add_pc             : Fun ["offset" :: ty.int] ty.unit
+   | read_mem           : Fun ["c" :: ty.cap] ty.memval
+   | write_mem          : Fun ["c" :: ty.cap; "v" :: ty.memval] ty.unit
+   | read_allowed       : Fun ["p" :: ty.perm] ty.bool
+   | write_allowed      : Fun ["p" :: ty.perm] ty.bool
+   | within_bounds      : Fun ["c" :: ty.cap] ty.bool
+   | perm_to_bits       : Fun ["p" :: ty.perm] ty.int
+   | perm_from_bits     : Fun ["i" :: ty.int] ty.perm
+   | and_perm           : Fun ["p1" :: ty.perm; "p2" :: ty.perm] ty.perm
+   | is_sub_perm        : Fun ["p" :: ty.perm; "p'" :: ty.perm] ty.bool
+   | is_within_range    : Fun ["b'" :: ty.addr; "e'" :: ty.addr; "b" :: ty.addr; "e" :: ty.addr] ty.bool
+   | abs                : Fun ["i" :: ty.int] ty.int
+   | is_not_zero        : Fun ["i" :: ty.int] ty.bool
+   | can_incr_cursor    : Fun ["c" :: ty.cap; "imm" :: ty.int] ty.bool
+   | exec_jalr_cap      : Fun ["cd"  :: ty.dst; "cs"  :: ty.src] ty.bool
+   | exec_cjalr         : Fun ["cd"  :: ty.dst; "cs"  :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_cjal          : Fun ["cd"  :: ty.dst; "imm" :: ty.int] ty.bool
+   | exec_bne           : Fun ["rs1" :: ty.src; "rs2" :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_ld            : Fun ["cd"  :: ty.dst; "cs"  :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_sd            : Fun ["rs1" :: ty.src; "rs2" :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_addi          : Fun ["rd"  :: ty.dst; "rs"  :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_add           : Fun ["rd"  :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool
+   | exec_sub           : Fun ["rd"  :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool
+   | exec_slt           : Fun ["rd"  :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool
+   | exec_slti          : Fun ["rd"  :: ty.dst; "rs"  :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_sltu          : Fun ["rd"  :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool
+   | exec_sltiu         : Fun ["rd"  :: ty.dst; "rs"  :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_cmove         : Fun ["cd"  :: ty.dst; "cs"  :: ty.src ] ty.bool
+   | exec_cincoffset    : Fun ["cd"  :: ty.dst; "cs"  :: ty.src; "rs"  :: ty.src] ty.bool
+   | exec_candperm      : Fun ["cd"  :: ty.dst; "cs"  :: ty.src; "rs"  :: ty.src] ty.bool
+   | exec_csetbounds    : Fun ["cd"  :: ty.dst; "cs"  :: ty.src; "rs"  :: ty.src] ty.bool
+   | exec_csetboundsimm : Fun ["cd"  :: ty.dst; "cs"  :: ty.src; "imm" :: ty.int] ty.bool
+   | exec_cgettag       : Fun ["rd"  :: ty.dst; "cs"  :: ty.src] ty.bool
+   | exec_cgetperm      : Fun ["rd"  :: ty.dst; "cs"  :: ty.src] ty.bool
+   | exec_cgetbase      : Fun ["rd"  :: ty.dst; "cs"  :: ty.src] ty.bool
+   | exec_cgetlen       : Fun ["rd"  :: ty.dst; "cs"  :: ty.src] ty.bool
+   | exec_cgetaddr      : Fun ["rd"  :: ty.dst; "cs"  :: ty.src] ty.bool
+   | exec_fail          : Fun [] ty.bool
+   | exec_ret           : Fun [] ty.bool
+   | exec_instr         : Fun ["i" :: ty.instr] ty.bool
+   | exec               : Fun [] ty.bool
+   | step               : Fun [] ty.unit
+   | loop               : Fun [] ty.unit
+   .
+ 
-   Inductive FunX : PCtx -> Ty -> Set :=
-   (* read memory *)
-   | rM    : FunX ["address" :: ty.int] ty.memval
-   (* write memory *)
-   | wM    : FunX ["address" :: ty.int; "new_value" :: ty.memval] ty.unit
-   | dI    : FunX ["code" :: ty.int] ty.instr
-   .
- 
-   Inductive Lem : PCtx -> Set :=
-   | open_gprs                  : Lem []
-   | close_gprs                 : Lem []
-   | safe_move_cursor           : Lem ["c'" :: ty.cap; "c" :: ty.cap]
-   | safe_sub_perm              : Lem ["c'" :: ty.cap; "c" :: ty.cap]
-   | safe_within_range          : Lem ["c'" :: ty.cap; "c" :: ty.cap]
-   | int_safe                   : Lem ["i" :: ty.int]
-   | correctPC_subperm_R        : Lem ["c" :: ty.cap]
-   | subperm_not_E              : Lem ["p" :: ty.perm; "p'" :: ty.perm]
-   | safe_to_execute            : Lem ["c" :: ty.cap]
-   .
- 
-   Definition 𝑭  : PCtx -> Ty -> Set := Fun.
-   Definition 𝑭𝑿  : PCtx -> Ty -> Set := FunX.
-   Definition 𝑳  : PCtx -> Set := Lem.
- 
+ End FunDeclKit.
- 
- Include FunDeclMixin MinCapsBase.
- 
+ Section FunDefKit.
+ 
+   Local Coercion stm_exp : Exp >-> Stm.
+ 
-   Local Notation "'a'"  := (@exp_var _ "a" _ _) : exp_scope.
-   Local Notation "'c'"  := (@exp_var _ "c" _ _) : exp_scope.
-   Local Notation "'e'"  := (@exp_var _ "e" _ _) : exp_scope.
-   Local Notation "'i'"  := (@exp_var _ "i" _ _) : exp_scope.
-   Local Notation "'n'"  := (@exp_var _ "n" _ _) : exp_scope.
-   Local Notation "'p'"  := (@exp_var _ "p" _ _) : exp_scope.
-   Local Notation "'p1'" := (@exp_var _ "p1" _ _) : exp_scope.
-   Local Notation "'p2'" := (@exp_var _ "p2" _ _) : exp_scope.
-   Local Notation "'q'"  := (@exp_var _ "q" _ _) : exp_scope.
-   Local Notation "'r'"  := (@exp_var _ "r" _ _) : exp_scope.
-   Local Notation "'w'"  := (@exp_var _ "w" _ _) : exp_scope.
-   Local Notation "'x'"  := (@exp_var _ "x" _ _) : exp_scope.
-   Local Notation "'immediate'" := (@exp_var _ "immediate" _ _) : exp_scope.
-   Local Notation "'offset'" := (@exp_var _ "offset" _ _) : exp_scope.
- 
-   Local Notation "'c'"  := "c" : string_scope.
-   Local Notation "'e'"  := "e" : string_scope.
-   Local Notation "'hv'" := "hv" : string_scope.
-   Local Notation "'rv'" := "rv" : string_scope.
-   Local Notation "'i'"  := "i" : string_scope.
-   Local Notation "'n'"  := "n" : string_scope.
-   Local Notation "'p'"  := "p" : string_scope.
-   Local Notation "'q'"  := "q" : string_scope.
-   Local Notation "'r'"  := "r" : string_scope.
-   Local Notation "'w'"  := "w" : string_scope.
-   Local Notation "'immediate'" := "immediate" : string_scope.
-   Local Notation "'offset'" := "offset" : string_scope.
- 
-   Notation "'use' 'lemma' f args" := (stm_lemma f args%env) (at level 10, f at next level) : exp_scope.
-   Notation "'use' 'lemma' f" := (stm_lemma f env.nil) (at level 10, f at next level) : exp_scope.
- 
-   (* NOTE: need to wrap s around parentheses when using this notation (not a real let binding!) *)
-   Notation "'let*:' '[' perm ',' beg ',' en ',' cur ']' ':=' cap 'in' s" :=
-     (stm_match_record capability cap
-       (recordpat_snoc (recordpat_snoc (recordpat_snoc (recordpat_snoc recordpat_nil
-        "cap_permission" perm)
-        "cap_begin" beg)
-        "cap_end" en)
-        "cap_cursor" cur)
-     s) (at level 10) : exp_scope.
- 
-   Definition lemma_correctPC_not_E {Γ} (cap : Stm Γ ty.cap) : Stm Γ ty.unit :=
-     let: "c" := cap in
-     use lemma correctPC_subperm_R [exp_var "c"] ;;
-     let*: ["perm" , "beg" , "end" , "cur"] := (exp_var "c") in
-     (let: "tmp" := exp_val ty.perm R in
-      use lemma subperm_not_E [exp_var "tmp"; exp_var "perm"]).
- 
+   Definition fun_read_reg : Stm ["rs" :: ty.enum regname] ty.word :=
-     use lemma open_gprs ;;
+     let: "x" := match: exp_var "rs" in regname with
+                 | R0 =>
+                     use lemma int_safe [exp_val ty.int 0%Z] ;;
+                     exp_inl (exp_val ty.int 0%Z)
+                 | R1 => stm_read_register reg1
+                 | R2 => stm_read_register reg2
+                 | R3 => stm_read_register reg3
+                 end in
-     use lemma close_gprs ;;
+     stm_exp x.
- 
-   Definition fun_read_reg_cap : Stm ["cs" :: ty.enum regname] ty.cap :=
+     let: w := call read_reg (exp_var "cs") in
+     match: w with
+     | inl i => fail "Err [read_reg_cap]: expect register to hold a capability"
+     | inr c =>
-         let*: ["p", "b", "e", "a"] := exp_var "c" in (* force record *)
+         (exp_var "c")
+     end.
- 
-   Definition fun_read_reg_num : Stm ["rs" :: ty.enum regname ] ty.int :=
+     let: w := call read_reg (exp_var "rs") in
+     match: w with
+     | inl i => stm_exp i
+     | inr c => fail "Err [read_reg_num]: expect register to hold a number"
+     end.
- 
-   Definition fun_write_reg : Stm ["rd" :: ty.enum regname; "w" :: ty.word] ty.unit :=
-     use lemma open_gprs ;;
+     match: exp_var "rd" in regname with
+     | R0 => stm_val ty.unit tt
+     | R1 => stm_write_register reg1 (exp_var "w") ;; stm_val ty.unit tt
+     | R2 => stm_write_register reg2 (exp_var "w") ;; stm_val ty.unit tt
+     | R3 => stm_write_register reg3 (exp_var "w") ;; stm_val ty.unit tt
+     end ;;
-     use lemma close_gprs.
- 
+   Definition fun_next_pc : Stm [] ty.cap :=
+     let: "c" := stm_read_register pc in
+     let*: ["perm" , "beg" , "end" , "cur"] := (exp_var "c") in
+       (exp_record capability
+          [ exp_var "perm";
+            exp_var "beg";
+            exp_var "end";
+            exp_var "cur" + exp_int 1 ]).
- 
+   Definition fun_update_pc : Stm [] ty.unit :=
+     let: "opc" := stm_read_register pc in
+     let: "npc" := call next_pc in
-     lemma_correctPC_not_E (exp_var "opc") ;;
-     use lemma safe_move_cursor [exp_var "npc"; exp_var "opc"] ;;
+     stm_write_register pc (exp_var "npc") ;;
+     stm_val ty.unit tt.
- 
+   Definition fun_update_pc_perm : Stm ["c" :: ty.cap] ty.cap :=
-     let*: ["p" , "b" , "e" , "a"] := (exp_var "c") in
+     (match: exp_var "p" in permission with
+      | E => let: "p" := exp_val ty.perm R in
-             use lemma safe_to_execute [exp_var "c"] ;;
+             exp_record capability
+                        [ exp_var "p" ;
+                          exp_var "b" ;
+                          exp_var "e" ;
+                          exp_var "a" ]
+      | _ => exp_var "c"
+      end).
- 
+   Definition fun_is_correct_pc : Stm ["c" :: ty.cap] ty.bool :=
-     let*: ["perm" , "beg" , "end" , "cur"] := (exp_var "c") in
+     (let: "tmp1" := call is_perm (exp_var "perm") (exp_val ty.perm R) in
+      let: "tmp2" := call is_perm (exp_var "perm") (exp_val ty.perm RW) in
+      if: (exp_var "beg" <= exp_var "cur") && (exp_var "cur" < exp_var "end")
+           && (exp_var "tmp1" || exp_var "tmp2")
+      then stm_val ty.bool true
+      else stm_val ty.bool false).
+ 
+   Definition fun_is_perm : Stm ["p" :: ty.perm; "p'" :: ty.perm] ty.bool :=
-     stm_match_enum permission (exp_var "p") (fun _ => stm_val ty.unit tt) ;;
-     stm_match_enum permission (exp_var "p'") (fun _ => stm_val ty.unit tt) ;;
+     exp_var "p" = exp_var "p'".
- 
+   Definition fun_add_pc : Stm ["offset" :: ty.int] ty.unit :=
+     let: "opc" := stm_read_register pc in
+     let*: ["perm", "beg", "end", "cur"] := (exp_var "opc") in
+     (let: "npc" := (exp_record capability
+                                [ exp_var "perm";
+                                  exp_var "beg";
+                                  exp_var "end";
+                                  exp_var "cur" + exp_var "offset" ]) in
-      lemma_correctPC_not_E (exp_var "opc") ;;
-      use lemma safe_move_cursor [exp_var "npc"; exp_var "opc"] ;;
+      stm_write_register pc (exp_var "npc") ;;
+      stm_val ty.unit tt).
- 
+   Definition fun_read_allowed : Stm ["p" :: ty.perm] ty.bool :=
+     call is_sub_perm (exp_val (ty.enum permission) R) (exp_var "p").
+ 
+   Definition fun_write_allowed : Stm ["p" :: ty.perm] ty.bool :=
+     call is_sub_perm (exp_val (ty.enum permission) RW) (exp_var "p").
+ 
+   Definition fun_within_bounds : Stm ["c" :: ty.cap] ty.bool :=
-     let*: ["p", "b", "e", "a"] := (exp_var "c") in
+     ((exp_var "b" <= exp_var "a") && (exp_var "a" <= exp_var "e")).
- 
-   Section ExecStore.
- 
-     Local Notation "'perm'"   := "cap_permission" : string_scope.
-     Local Notation "'cursor'" := "cap_cursor" : string_scope.
- 
-     Let cap : Ty := ty.cap.
-     Let bool : Ty := ty.bool.
-     Let int : Ty := ty.int.
-     Let word : Ty := ty.word.
- 
-     Definition fun_exec_sd : Stm ["rs1" :: ty.src; "rs2" :: ty.src; "imm" :: ty.int] ty.bool :=
+       let: "base_cap" :: cap  := call read_reg_cap (exp_var "rs1") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "base_cap") in
+       (let: "c" :: cap := exp_record capability
+                                      [ exp_var "perm";
+                                        exp_var "beg";
+                                        exp_var "end";
+                                        exp_var "cursor" + exp_var "imm"
+                                      ] in
+        let: p :: bool := call write_allowed (exp_var "perm") in
-        stm_assert p (exp_string "Err: [store] no write permission") ;;
+        let: w :: ty.word := call read_reg (exp_var "rs2") in
+        let: "tmp" := exp_val ty.perm RW in
-        use lemma subperm_not_E [exp_var "tmp"; exp_var "perm"] ;;
-        use lemma safe_move_cursor [exp_var "c"; exp_var "base_cap"] ;;
+        call write_mem c w ;;
+        call update_pc ;;
+        stm_val ty.bool true).
- 
-     Definition fun_exec_ld : Stm ["cd" :: ty.dst; "cs" :: ty.src; "imm" :: ty.int] ty.bool :=
+       let: "base_cap" :: cap  := call read_reg_cap (exp_var "cs") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "base_cap") in
+       (let: "c" :: cap := exp_record capability
+                                      [ exp_var "perm";
+                                        exp_var "beg";
+                                        exp_var "end";
+                                        exp_var "cursor" + exp_var "imm"
+                                      ] in
+        let: p :: bool := call read_allowed (exp_var "perm") in
-        stm_assert p (exp_string "Err: [load] no read permission") ;;                 
+        let: "tmp" := exp_val ty.perm R in
-        use lemma subperm_not_E [exp_var "tmp"; exp_var "perm"] ;;
-        use lemma safe_move_cursor [exp_var "c"; exp_var "base_cap"] ;;
-        let: n :: ty.memval := call read_mem c in
+        call write_reg (exp_var "cd") n ;;
+        call update_pc ;;
+        stm_val ty.bool true).
- 
-     Definition fun_exec_cincoffset : Stm ["cd" :: ty.dst; "cs" :: ty.src; "rs" :: ty.src] ty.bool :=
+       let: "base_cap" :: cap  := call read_reg_cap (exp_var "cs") in
+       let: "offset" :: ty.int := call read_reg_num (exp_var "rs") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "base_cap") in
+       (match: exp_var "perm" in permission with
+        | E => fail "Err: [cincoffset] not permitted on enter capability"
+        | _ =>
+            let: "c" :: cap := exp_record capability
+                                          [ exp_var "perm";
+                                            exp_var "beg";
+                                            exp_var "end";
+                                            exp_var "cursor" + exp_var "offset"
+                                          ] in
-            use lemma safe_move_cursor [exp_var "c"; exp_var "base_cap"] ;;
+            call write_reg (exp_var "cd") (exp_inr (exp_var "c")) ;;
+            call update_pc ;;
+            stm_val ty.bool true
+        end).
- 
-     Definition fun_exec_candperm : Stm ["cd" :: ty.dst; "cs" :: ty.src; "rs" :: ty.src] ty.bool :=
+       let: "cs_val" := call read_reg_cap (exp_var "cs") in
+       let: "rs_val" := call read_reg_num (exp_var "rs") in
-       let*: ["p", "b", "e", "a"] := exp_var "cs_val" in
+       let: "p'" := call perm_from_bits (exp_var "rs_val") in
+       let: "new_p"  := call and_perm (exp_var "p") (exp_var "p'") in
-       let: "new_cap" :: cap := exp_record capability
+                                           [ exp_var "new_p";
+                                             exp_var "b";
+                                             exp_var "e";
+                                             exp_var "a"
+                                           ] in
-       use lemma safe_sub_perm [exp_var "new_cap"; exp_var "cs_val"] ;;
+       call write_reg (exp_var "cd") (exp_inr (exp_var "new_cap")) ;;
+       stm_val ty.bool true.
- 
-     Definition fun_exec_addi : Stm ["rd" :: ty.dst; "rs" :: ty.src; "imm" :: ty.int] ty.bool :=
-       let: "v" :: ty.int := call read_reg_num (exp_var "rs") in
-       let: "res" :: ty.int := stm_exp (exp_var "v" + exp_var "imm") in
-       use lemma int_safe [exp_var "res"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "res")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_add : Stm ["rd" :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool :=
-       let: "v1" :: int := call read_reg_num (exp_var "rs1") in
-       let: "v2" :: int := call read_reg_num (exp_var "rs2") in
-       let: "res" :: int := stm_exp (exp_var "v1" + exp_var "v2") in
-       use lemma int_safe [exp_var "res"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "res")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_sub : Stm ["rd" :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool :=
-       let: "v1" :: int := call read_reg_num (exp_var "rs1") in
-       let: "v2" :: int := call read_reg_num (exp_var "rs2") in
-       let: "res" :: int := stm_exp (exp_var "v1" - exp_var "v2") in
-       use lemma int_safe [exp_var "res"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "res")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_abs : Stm ["i" :: ty.int] ty.int :=
-       if: exp_var "i" < (exp_val ty.int 0%Z)
-       then exp_var "i" * (exp_val ty.int (-1)%Z)
-       else exp_var "i".
- 
-     Definition fun_is_not_zero : Stm ["i" :: ty.int] ty.bool :=
-       if: exp_var "i" = exp_val ty.int 0%Z
-       then stm_val ty.bool false
-       else stm_val ty.bool true.
- 
-     Definition fun_can_incr_cursor : Stm ["c" :: ty.cap; "imm" :: ty.int] ty.bool :=
-       let*: ["p", "b", "e", "a"] := exp_var "c" in
-       let: "tmp1" := call is_perm (exp_var "p") (exp_val ty.perm E) in
-       if: exp_var "tmp1"
-       then
-         let: "tmp2" := call is_not_zero (exp_var "imm") in
-         if: exp_var "tmp2"
-         then stm_val ty.bool false
-         else
-           stm_val ty.bool true
-       else stm_val ty.bool true.
- 
-     Definition fun_exec_slt : Stm ["rd" :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool :=
-       let: "v1" :: int := call read_reg_num (exp_var "rs1") in
-       let: "v2" :: int := call read_reg_num (exp_var "rs2") in
-       (if: exp_var "v1" < exp_var "v2"
-        then
-          use lemma int_safe [exp_val ty.int 1%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 1%Z))
-        else
-          use lemma int_safe [exp_val ty.int 0%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 0%Z))) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_slti : Stm ["rd" :: ty.dst; "rs" :: ty.src; "imm" :: ty.int] ty.bool :=
-       let: "v1" :: int := call read_reg_num (exp_var "rs") in
-       let: "v2" :: int := exp_var "imm" in
-       (if: exp_var "v1" < exp_var "v2"
-        then
-          use lemma int_safe [exp_val ty.int 1%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 1%Z))
-        else
-          use lemma int_safe [exp_val ty.int 0%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 0%Z))) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_sltu : Stm ["rd" :: ty.dst; "rs1" :: ty.src; "rs2" :: ty.src] ty.bool :=
-       let: "v1" :: int := call read_reg_num (exp_var "rs1") in
-       let: "uv1" :: int := call abs (exp_var "v1") in
-       let: "v2" :: int := call read_reg_num (exp_var "rs2") in
-       let: "uv2" :: int := call abs (exp_var "v2") in
-       (if: exp_var "uv1" < exp_var "uv2"
-        then
-          use lemma int_safe [exp_val ty.int 1%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 1%Z))
-        else
-          use lemma int_safe [exp_val ty.int 0%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 0%Z))) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_sltiu : Stm ["rd" :: ty.dst; "rs" :: ty.src; "imm" :: ty.int] ty.bool :=
-       let: "v1" :: int := call read_reg_num (exp_var "rs") in
-       let: "uv1" :: int := call abs (exp_var "v1") in
-       let: "v2" :: int := exp_var "imm" in
-       let: "uv2" :: int := call abs (exp_var "v2") in
-       (if: exp_var "uv1" < exp_var "uv2"
-        then
-          use lemma int_safe [exp_val ty.int 1%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 1%Z))
-        else
-          use lemma int_safe [exp_val ty.int 0%Z] ;;
-          call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 0%Z))) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_perm_to_bits : Stm ["p" :: ty.perm] ty.int :=
-       match: exp_var "p" in permission with
-       | O  => stm_val ty.int 0%Z
-       | R  => stm_val ty.int 1%Z
-       | RW => stm_val ty.int 2%Z
-       | E  => stm_val ty.int 3%Z
-       end.
- 
-     Definition fun_perm_from_bits : Stm ["i" :: ty.int] ty.perm :=
-       if: exp_var "i" = exp_val ty.int 1%Z
-       then exp_val ty.perm R
-       else if: exp_var "i" = exp_val ty.int 2%Z
-            then exp_val ty.perm RW
-            else if: exp_var "i" = exp_val ty.int 3%Z
-                 then exp_val ty.perm E
-                 else exp_val ty.perm O.
- 
-     Definition fun_and_perm : Stm ["p1" :: ty.perm; "p2" :: ty.perm] ty.perm :=
-       match: exp_var "p1" in permission with
-       | O  => exp_val ty.perm O
-       | R  => match: exp_var "p2" in permission with
-               | R  => exp_val ty.perm R
-               | RW => exp_val ty.perm R
-               | _  => exp_val ty.perm O
-               end
-       | RW => match: exp_var "p2" in permission with
-               | R  => exp_val ty.perm R
-               | RW => exp_val ty.perm RW
-               | _  => exp_val ty.perm O
-               end
-       | E  => match: exp_var "p2" in permission with
-               | E => exp_val ty.perm E
-               | _ => exp_val ty.perm O
-               end
-       end.
- 
-     Definition fun_is_sub_perm : Stm ["p" :: ty.perm; "p'" :: ty.perm] ty.bool :=
-       match: exp_var "p" in permission with
-       | O =>
-         stm_val ty.bool true
-       | E => match: exp_var "p'" in permission with
-              | O => stm_val ty.bool false
-              | _ => stm_val ty.bool true
-              end
-       | R => match: exp_var "p'" in permission with
-             | O => stm_val ty.bool false
-             | E => stm_val ty.bool false
-             | _ =>
-               stm_val ty.bool true
-             end
-       | RW => match: exp_var "p'" in permission with
-              | RW =>
-                stm_val ty.bool true
-             | _ => stm_val ty.bool false
-             end
-       end.
- 
-     Definition fun_is_within_range : Stm ["b'" :: ty.addr; "e'" :: ty.addr;
-                                           "b" :: ty.addr; "e" :: ty.addr] ty.bool :=
-       (exp_var "b" <= exp_var "b'") && (exp_var "e'" <= exp_var "e").
- 
-     Definition fun_exec_csetbounds : Stm ["cd" :: ty.dst; "cs" :: ty.src; "rs" :: ty.src] ty.bool :=
-       let: c :: cap := call read_reg_cap (exp_var "cs") in
-       let*: ["p", "b", "e", "a"] := exp_var "c" in
-       let: "new_begin" :: ty.int :=  exp_var "a" in
-       let: "rs_val" :: ty.int := call read_reg_num (exp_var "rs") in
-       let: "new_end" :: ty.int := (exp_var "new_begin") + (exp_var "rs_val") in
-       match: exp_var "p" in permission with
-        | E => fail "Err: [csetbounds] not permitted on enter capability"
-        | _ =>
-            let: "b" :: ty.bool :=
-              call is_within_range (exp_var "new_begin") (exp_var "new_end")
-                                   (exp_var "b")         (exp_var "e") in
-            stm_assert (exp_var "b") (exp_string "Err: [csetbounds] tried to increase range of authority") ;;
-            let: "c'" :: cap := exp_record capability
-                                           [ exp_var "p";
-                                             exp_var "new_begin";
-                                             exp_var "new_end";
-                                             exp_var "a"
-                                           ] in
-            use lemma safe_within_range [exp_var "c'"; exp_var "c"] ;;
-            call write_reg (exp_var "cd") (exp_inr (exp_var "c'")) ;;
-            call update_pc ;;
-            stm_val ty.bool true
-        end.
- 
-     Definition fun_exec_csetboundsimm : Stm ["cd" :: ty.dst; "cs" :: ty.src; "imm" :: ty.int] ty.bool :=
-       let: c :: cap := call read_reg_cap (exp_var "cs") in
-       let*: ["p", "b", "e", "a"] := exp_var "c" in
-       let: "new_begin" :: ty.int :=  exp_var "a" in
-       let: "new_end" :: ty.int := (exp_var "new_begin") + (exp_var "imm") in
-       match: exp_var "p" in permission with
-        | E => fail "Err: [csetboundsimm] not permitted on enter capability"
-        | _ =>
-            let: "b" :: ty.bool :=
-              call is_within_range (exp_var "new_begin") (exp_var "new_end")
-                                   (exp_var "b")         (exp_var "e") in
-            stm_assert (exp_var "b") (exp_string "Err: [csetboundsimm] tried to increase range of authority") ;;
-            let: "c'" :: cap := exp_record capability
-                                           [ exp_var "p";
-                                             exp_var "new_begin";
-                                             exp_var "new_end";
-                                             exp_var "a"
-                                           ] in
-            use lemma safe_within_range [exp_var "c'"; exp_var "c"] ;;
-            call write_reg (exp_var "cd") (exp_inr (exp_var "c'")) ;;
-            call update_pc ;;
-            stm_val ty.bool true
-        end.
- 
-     Definition fun_exec_cgettag : Stm ["rd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       let: w :: ty.word := call read_reg (exp_var "cs") in
-       match: w with
-       | inl i =>
-         use lemma int_safe [exp_val ty.int 0%Z] ;;
-         call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 0%Z))
-       | inr c =>
-         use lemma int_safe [exp_val ty.int 1%Z] ;;
-         call write_reg (exp_var "rd") (exp_inl (exp_val ty.int 1%Z))
-       end ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_cgetperm : Stm ["rd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       let: c :: cap := call read_reg_cap (exp_var "cs") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-       let: "i" :: ty.int := call perm_to_bits (exp_var "perm") in
-       use lemma int_safe [exp_var "i"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "i")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_cgetbase : Stm ["rd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       let: c :: cap := call read_reg_cap (exp_var "cs") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-       use lemma int_safe [exp_var "beg"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "beg")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_cgetlen : Stm ["rd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       let: c :: cap := call read_reg_cap (exp_var "cs") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-       let: "res" := (exp_var "end") - (exp_var "beg") in
-       use lemma int_safe [exp_var "res"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "res")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_cgetaddr : Stm ["rd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       let: c :: cap := call read_reg_cap (exp_var "cs") in
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-       use lemma int_safe [exp_var "cursor"] ;;
-       call write_reg (exp_var "rd") (exp_inl (exp_var "cursor")) ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_fail : Stm [] ty.bool :=
-       fail "machine failed".
- 
-     Definition fun_exec_ret : Stm [] ty.bool :=
-       stm_exp exp_false.
- 
-     Definition fun_exec_cmove : Stm ["cd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       let: w :: word := call read_reg (exp_var "cs") in
-       call write_reg (exp_var "cd") w ;;
-       call update_pc ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_jalr_cap : Stm ["cd" :: ty.dst; "cs" :: ty.src] ty.bool :=
-       call exec_cjalr (exp_var "cd") (exp_var "cs") (exp_val ty.int 0%Z).
- 
-     Definition fun_exec_cjalr : Stm ["cd" :: ty.dst; "cs" :: ty.src; "imm" :: ty.int] ty.bool :=
-       let: "opc" := stm_read_register pc in
-       let: "npc" := call next_pc in
-       lemma_correctPC_not_E (exp_var "opc") ;;
-       use lemma safe_move_cursor [exp_var "npc"; exp_var "opc"] ;;
-       call write_reg (exp_var "cd") (exp_inr (exp_var "npc")) ;;
-       let: "c" :: ty.cap := call read_reg_cap (exp_var "cs") in
-       let*: ["p", "b", "e", "a"] := exp_var "c" in
-       let: "tmp" := call can_incr_cursor (exp_var "c") (exp_var "imm") in
-       if: exp_not (exp_var "tmp")
-       then fail "Err: [cjalr] cannot increment cursor of enter capability"
-       else
-         let: "c'" := (exp_record capability
-                                  [ exp_var "p";
-                                    exp_var "b";
-                                    exp_var "e";
-                                    exp_var "a" + exp_var "imm"]) in
-         use lemma safe_move_cursor [exp_var "c'"; exp_var "c"] ;;
-         let: "c'" := call update_pc_perm (exp_var "c'") in
-         stm_write_register pc (exp_var "c'") ;;
-         stm_val ty.bool true.
- 
-     Definition fun_exec_cjal : Stm ["cd" :: ty.dst; "imm" :: ty.int] ty.bool :=
-       let: "opc" := stm_read_register pc in
-       let: "npc" := call next_pc in
-       lemma_correctPC_not_E (exp_var "opc") ;;
-       use lemma safe_move_cursor [exp_var "npc"; exp_var "opc"] ;;
-       call write_reg (exp_var "cd") (exp_inr (exp_var "npc")) ;;
-       call add_pc (exp_binop bop.times (exp_var "imm") (exp_int 2)) ;;
-       stm_val ty.bool true.
- 
-     Definition fun_exec_bne : Stm ["rs1" :: ty.src; "rs2" :: ty.src; "imm" :: ty.int] ty.bool :=
-       let: "a" :: ty.int := call read_reg_num (exp_var "rs1") in
-       let: "b" :: ty.int := call read_reg_num (exp_var "rs2") in
-       stm_if (exp_var "a" = exp_var "b")
-              (call update_pc ;; stm_val ty.bool true)
-              (call add_pc (exp_var "imm") ;; stm_val ty.bool true).
- 
-     Definition fun_exec_instr : Stm [i :: ty.instr] ty.bool :=
-       stm_match_union_alt
-         instruction (exp_var i)
-         (fun K =>
-            match K with
-            | kjalr_cap      => MkAlt (pat_pair "cd" "cs")
-                                      (call exec_jalr_cap (exp_var "cd") (exp_var "cs"))%exp
-            | kcjalr         => MkAlt (pat_tuple ("cd" , "cs" , "imm"))
-                                      (call exec_cjalr (exp_var "cd") (exp_var "cs") (exp_var "imm"))%exp
-            | kcjal          => MkAlt (pat_pair "cd" "imm")
-                                      (call exec_cjal (exp_var "cd") (exp_var "imm"))%exp
-            | kbne           => MkAlt (pat_tuple ("rs1" , "rs2" , "imm"))
-                                      (call exec_bne (exp_var "rs1") (exp_var "rs2") (exp_var "imm"))%exp
-            | kcmove         => MkAlt (pat_pair "cd" "cs")
-                                      (call exec_cmove (exp_var "cd") (exp_var "cs"))%exp
-            | kld            => MkAlt (pat_tuple ("cd" , "cs" , "imm"))
-                                      (call exec_ld (exp_var "cd") (exp_var "cs") (exp_var "imm"))%exp
-            | ksd            => MkAlt (pat_tuple ("rs1" , "rs2" , "imm"))
-                                      (call exec_sd (exp_var "rs1") (exp_var "rs2") (exp_var "imm"))%exp
-            | kcincoffset    => MkAlt (pat_tuple ("cd" , "cs" , "rs"))
-                                      (call exec_cincoffset (exp_var "cd") (exp_var "cs") (exp_var "rs"))%exp
-            | kcandperm      => MkAlt (pat_tuple ("cd" , "cs" , "rs"))
-                                      (call exec_candperm (exp_var "cd") (exp_var "cs") (exp_var "rs"))%exp
-            | kcsetbounds    => MkAlt (pat_tuple ("cd" , "cs" , "rs"))
-                                      (call exec_csetbounds (exp_var "cd") (exp_var "cs") (exp_var "rs"))%exp
-            | kcsetboundsimm => MkAlt (pat_tuple ("cd" , "cs" , "imm"))
-                                      (call exec_csetboundsimm (exp_var "cd") (exp_var "cs") (exp_var "imm"))%exp
-            | kaddi          => MkAlt (pat_tuple ("rd" , "rs" , "imm"))
-                                      (call exec_addi (exp_var "rd") (exp_var "rs") (exp_var "imm"))%exp
-            | kadd           => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
-                                      (call exec_add (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
-            | ksub           => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
-                                      (call exec_sub (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
-            | kslt           => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
-                                      (call exec_slt (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
-            | kslti          => MkAlt (pat_tuple ("rd" , "rs" , "imm"))
-                                      (call exec_slti (exp_var "rd") (exp_var "rs") (exp_var "imm"))%exp
-            | ksltu          => MkAlt (pat_tuple ("rd" , "rs1" , "rs2"))
-                                      (call exec_sltu (exp_var "rd") (exp_var "rs1") (exp_var "rs2"))%exp
-            | ksltiu         => MkAlt (pat_tuple ("rd" , "rs" , "imm"))
-                                      (call exec_sltiu (exp_var "rd") (exp_var "rs") (exp_var "imm"))%exp
-            | kcgettag       => MkAlt (pat_pair "rd" "cs")
-                                      (call exec_cgettag (exp_var "rd") (exp_var "cs"))%exp
-            | kcgetperm      => MkAlt (pat_pair "rd" "cs")
-                                      (call exec_cgetperm (exp_var "rd") (exp_var "cs"))%exp
-            | kcgetbase      => MkAlt (pat_pair "rd" "cs")
-                                      (call exec_cgetbase (exp_var "rd") (exp_var "cs"))%exp
-            | kcgetlen       => MkAlt (pat_pair "rd" "cs")
-                                      (call exec_cgetlen (exp_var "rd") (exp_var "cs"))%exp
-            | kcgetaddr      => MkAlt (pat_pair "rd" "cs")
-                                      (call exec_cgetaddr (exp_var "rd") (exp_var "cs"))%exp
-            | kfail          => MkAlt pat_unit
-                                      (call exec_fail)%exp
-            | kret           => MkAlt pat_unit
-                                      (call exec_ret)%exp
-            end).
- 
-     Definition fun_read_mem : Stm ["c" ∷ ty.cap] ty.memval :=
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-       (let: q :: bool := call within_bounds c in
-        stm_assert q (exp_string "Err: [read_mem] out of bounds") ;;
-        foreign rM (exp_var "cursor")).
- 
-     Definition fun_write_mem : Stm ["c" ∷ ty.cap; "v" ∷ ty.memval] ty.unit :=
-       let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-       (let: q :: bool := call within_bounds c in
-        stm_assert q (exp_string "Err: [write_mem] out of bounds") ;;
-        foreign wM (exp_var "cursor") (exp_var "v")).
- 
-     Definition fun_exec : Stm [] ty.bool :=
-       let: "c" := stm_read_register pc in
-       (let*: ["perm", "beg", "end", "cursor"] := (exp_var "c") in
-        use lemma correctPC_subperm_R [exp_var "c"] ;;
-        let: n :: ty.memval := call read_mem c in
-        match: n with
-        | inl n => 
-            let: i :: ty.instr := foreign dI n in
-            call exec_instr i
-        | inr c => fail "Err [exec]: instructions cannot be capabilities"
-        end).
- 
-     Definition fun_step : Stm [] ty.unit :=
-       let: "tmp1" := stm_read_register pc in
-       let: "tmp2" := call is_correct_pc (exp_var "tmp1") in
-       if: exp_var "tmp2"
-       then
-         call exec ;;
-         stm_val ty.unit tt
-       else
-         fail "Err [step]: incorrect PC".
- 
-     Definition fun_loop : Stm [] ty.unit :=
-       call step ;; call loop.
- 
-   End ExecStore.
- 
-   Definition FunDef {Δ τ} (f : Fun Δ τ) : Stm Δ τ :=
-     match f with
-     | read_reg           => fun_read_reg
-     | read_reg_cap       => fun_read_reg_cap
-     | read_reg_num       => fun_read_reg_num
-     | write_reg          => fun_write_reg
-     | next_pc            => fun_next_pc
-     | update_pc          => fun_update_pc
-     | update_pc_perm     => fun_update_pc_perm
-     | is_correct_pc      => fun_is_correct_pc
-     | is_perm            => fun_is_perm
-     | add_pc             => fun_add_pc
-     | read_mem           => fun_read_mem
-     | write_mem          => fun_write_mem
-     | read_allowed       => fun_read_allowed
-     | write_allowed      => fun_write_allowed
-     | within_bounds      => fun_within_bounds
-     | perm_to_bits       => fun_perm_to_bits
-     | perm_from_bits     => fun_perm_from_bits
-     | and_perm           => fun_and_perm
-     | is_sub_perm        => fun_is_sub_perm
-     | is_within_range    => fun_is_within_range
-     | abs                => fun_abs
-     | is_not_zero        => fun_is_not_zero
-     | can_incr_cursor    => fun_can_incr_cursor
-     | exec_jalr_cap      => fun_exec_jalr_cap
-     | exec_cjalr         => fun_exec_cjalr
-     | exec_cjal          => fun_exec_cjal
-     | exec_bne           => fun_exec_bne
-     | exec_cmove         => fun_exec_cmove
-     | exec_ld            => fun_exec_ld
-     | exec_sd            => fun_exec_sd
-     | exec_cincoffset    => fun_exec_cincoffset
-     | exec_candperm      => fun_exec_candperm
-     | exec_csetbounds    => fun_exec_csetbounds
-     | exec_csetboundsimm => fun_exec_csetboundsimm
-     | exec_addi          => fun_exec_addi
-     | exec_add           => fun_exec_add
-     | exec_sub           => fun_exec_sub
-     | exec_slt           => fun_exec_slt
-     | exec_slti          => fun_exec_slti
-     | exec_sltu          => fun_exec_sltu
-     | exec_sltiu         => fun_exec_sltiu
-     | exec_cgettag       => fun_exec_cgettag
-     | exec_cgetperm      => fun_exec_cgetperm
-     | exec_cgetbase      => fun_exec_cgetbase
-     | exec_cgetlen       => fun_exec_cgetlen
-     | exec_cgetaddr      => fun_exec_cgetaddr
-     | exec_fail          => fun_exec_fail
-     | exec_ret           => fun_exec_ret
-     | exec_instr         => fun_exec_instr
-     | exec               => fun_exec
-     | step               => fun_step
-     | loop               => fun_loop
-     end.
- 
- End FunDefKit.
- 
- Include DefaultRegStoreKit MinCapsBase.
- 
- Section ForeignKit.
-   Definition fun_rM (μ : Memory) (addr : Val ty.int) : Val ty.memval :=
-     μ addr.
- 
-   Definition fun_wM (μ : Memory) (addr : Val ty.int) (val : Val ty.memval) : Memory :=
-     fun addr' => if Z.eqb addr addr' then val else μ addr'.
- 
-   (* We postulate a pure decode function and assume that that's what the decode primitive implements. *)
-   (* Similarly for *_{from,to}_bits functions, ideally we would move to actual bitvectors for values... *)
-   Axiom pure_decode : Z -> string + Instruction.
- 
-   #[derive(equations=no)]
-   Equations ForeignCall {σs σ} (f : 𝑭𝑿 σs σ) (args : NamedEnv Val σs) (res : string + Val σ) (γ γ' : RegStore) (μ μ' : Memory) : Prop :=
-     ForeignCall rM [addr] res γ γ' μ μ' :=
-       (γ' , μ' , res) = (γ , μ , inr (fun_rM μ addr));
-     ForeignCall wM [addr; val] res γ γ' μ μ' =>
-       (γ' , μ' , res) = (γ , fun_wM μ addr val , inr tt);
-     ForeignCall dI [code] res γ γ' μ μ' :=
-       (γ' , μ' , res) = (γ , μ , pure_decode code).
- 
-   Lemma ForeignProgress {σs σ} (f : 𝑭𝑿 σs σ) (args : NamedEnv Val σs) γ μ :
-     exists γ' μ' res, ForeignCall f args res γ γ' μ μ'.
-   Proof. destruct f; env.destroy args; repeat econstructor. Qed.
- End ForeignKit.
- 
- Include ProgramMixin MinCapsBase.
- 
- End MinCapsProgram.