(* Specification:

cx: register a_size
di: register a_size
al: register d_size
mem: memory of d_size bit words, addresses of a_size bits

while not(cx=0) do begin
  mem[di] <- al
  di <- di+1
  cx <- cx-1
end
*)

(****************************************************************)

Fixpoint di (st : nat) : BV -> BV -> BV -> Memo -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) =>
  match st return BV with
  | O => di0
  | S t =>
      match IsNull (cx t di0 cx0 al0 mem0) return BV with
      | true => di t di0 cx0 al0 mem0
      | false => BV_increment (di t di0 cx0 al0 mem0)
      end
  end
 
 with cx (st : nat) : BV -> BV -> BV -> Memo -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) =>
  match st return BV with
  | O => cx0
  | S t =>
      match IsNull (cx t di0 cx0 al0 mem0) return BV with
      | true => cx t di0 cx0 al0 mem0
      | false => BV_decrement (cx t di0 cx0 al0 mem0)
      end
  end
 
 with al (st : nat) : BV -> BV -> BV -> Memo -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) =>
  match st return BV with
  | O => al0
  | S t =>
      match IsNull (cx t di0 cx0 al0 mem0) return BV with
      | true => al t di0 cx0 al0 mem0
      | false => al t di0 cx0 al0 mem0
      end
  end
 
 with mem (st : nat) : BV -> BV -> BV -> Memo -> Memo :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) =>
  match st return Memo with
  | O => mem0
  | S t =>
      match IsNull (cx t di0 cx0 al0 mem0) return Memo with
      | true => mem t di0 cx0 al0 mem0
      | false =>
          MemoWrite (mem t di0 cx0 al0 mem0)
            (BV_to_nat (di t di0 cx0 al0 mem0)) (al t di0 cx0 al0 mem0)
      end
  end.

(* Specifications: *)
Lemma di_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo), di (S t) di0 cx0 al0 mem0 = match IsNull (cx t di0 cx0 al0 mem0) return BV with | true => di t di0 cx0 al0 mem0 | false => BV_increment (di t di0 cx0 al0 mem0) end.
Lemma cx_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo), cx (S t) di0 cx0 al0 mem0 = match IsNull (cx t di0 cx0 al0 mem0) return BV with | true => cx t di0 cx0 al0 mem0 | false => BV_decrement (cx t di0 cx0 al0 mem0) end.
Lemma al_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo), al (S t) di0 cx0 al0 mem0 = match IsNull (cx t di0 cx0 al0 mem0) return BV with | true => al t di0 cx0 al0 mem0 | false => al t di0 cx0 al0 mem0 end.
Lemma al_constant : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo), al t di0 cx0 al0 mem0 = al0.
Lemma mem_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo), mem (S t) di0 cx0 al0 mem0 = match IsNull (cx t di0 cx0 al0 mem0) return Memo with | true => mem t di0 cx0 al0 mem0 | false => MemoWrite (mem t di0 cx0 al0 mem0) (BV_to_nat (di t di0 cx0 al0 mem0)) (al t di0 cx0 al0 mem0) end.
Lemma length_di : forall t : nat, lengthbv (di t di_init cx_init al_init mem_init) = a_size.
Lemma length_cx : forall t : nat, lengthbv (cx t di_init cx_init al_init mem_init) = a_size.
Lemma length_al : forall t : nat, lengthbv (al t di_init cx_init al_init mem_init) = d_size.