(* Implementation:

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

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



(****************************************************************)
(* Implementation *)

(* seq1 *)

Definition di1 (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) := di0.Definition cx1 (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) := cx0.Definition al1 (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) := al0.Definition mem1 (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) := mem0.Definition ad1 (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) := di0.Definition da1 (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) := al0.(* seq2 *)

Fixpoint di2 (st : nat) : BV -> BV -> BV -> Memo -> BV -> BV -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) =>
  match st return BV with
  | O => di0
  | S t =>
      match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with
      | true => di2 t di0 cx0 al0 mem0 ad0 da0
      | false => di2 t di0 cx0 al0 mem0 ad0 da0
      end
  end
 
 with cx2 (st : nat) : BV -> BV -> BV -> Memo -> BV -> BV -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) =>
  match st return BV with
  | O => cx0
  | S t =>
      match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with
      | true => cx2 t di0 cx0 al0 mem0 ad0 da0
      | false => BV_decrement (cx2 t di0 cx0 al0 mem0 ad0 da0)
      end
  end
 
 with al2 (st : nat) : BV -> BV -> BV -> Memo -> BV -> BV -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) =>
  match st return BV with
  | O => al0
  | S t =>
      match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with
      | true => al2 t di0 cx0 al0 mem0 ad0 da0
      | false => al2 t di0 cx0 al0 mem0 ad0 da0
      end
  end
 
 with mem2 (st : nat) : BV -> BV -> BV -> Memo -> BV -> BV -> Memo :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) =>
  match st return Memo with
  | O => mem0
  | S t =>
      match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return Memo with
      | true => mem2 t di0 cx0 al0 mem0 ad0 da0
      | false =>
          MemoWrite (mem2 t di0 cx0 al0 mem0 ad0 da0)
            (BV_to_nat (ad2 t di0 cx0 al0 mem0 ad0 da0))
            (da2 t di0 cx0 al0 mem0 ad0 da0)
      end
  end
 
 with ad2 (st : nat) : BV -> BV -> BV -> Memo -> BV -> BV -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) =>
  match st return BV with
  | O => ad0
  | S t =>
      match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with
      | true => ad2 t di0 cx0 al0 mem0 ad0 da0
      | false => BV_increment (ad2 t di0 cx0 al0 mem0 ad0 da0)
      end
  end
 
 with da2 (st : nat) : BV -> BV -> BV -> Memo -> BV -> BV -> BV :=
  fun (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV) =>
  match st return BV with
  | O => da0
  | S t =>
      match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with
      | true => da2 t di0 cx0 al0 mem0 ad0 da0
      | false => da2 t di0 cx0 al0 mem0 ad0 da0
      end
  end.

(* Specifications: *)
Lemma di2_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), di2 (S t) di0 cx0 al0 mem0 ad0 da0 = match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with | true => di2 t di0 cx0 al0 mem0 ad0 da0 | false => di2 t di0 cx0 al0 mem0 ad0 da0 end.
Lemma di2_constant : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), di2 t di0 cx0 al0 mem0 ad0 da0 = di0.
Lemma cx2_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), cx2 (S t) di0 cx0 al0 mem0 ad0 da0 = match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with | true => cx2 t di0 cx0 al0 mem0 ad0 da0 | false => BV_decrement (cx2 t di0 cx0 al0 mem0 ad0 da0) end.
Lemma al2_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), al2 (S t) di0 cx0 al0 mem0 ad0 da0 = match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with | true => al2 t di0 cx0 al0 mem0 ad0 da0 | false => al2 t di0 cx0 al0 mem0 ad0 da0 end.
Lemma al2_constant : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), al2 t di0 cx0 al0 mem0 ad0 da0 = al0.
Lemma mem2_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), mem2 (S t) di0 cx0 al0 mem0 ad0 da0 = match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return Memo with | true => mem2 t di0 cx0 al0 mem0 ad0 da0 | false => MemoWrite (mem2 t di0 cx0 al0 mem0 ad0 da0) (BV_to_nat (ad2 t di0 cx0 al0 mem0 ad0 da0)) (da2 t di0 cx0 al0 mem0 ad0 da0) end.
Lemma ad2_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), ad2 (S t) di0 cx0 al0 mem0 ad0 da0 = match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with | true => ad2 t di0 cx0 al0 mem0 ad0 da0 | false => BV_increment (ad2 t di0 cx0 al0 mem0 ad0 da0) end.
Lemma da2_t : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), da2 (S t) di0 cx0 al0 mem0 ad0 da0 = match IsNull (cx2 t di0 cx0 al0 mem0 ad0 da0) return BV with | true => da2 t di0 cx0 al0 mem0 ad0 da0 | false => da2 t di0 cx0 al0 mem0 ad0 da0 end.
Lemma da2_constant : forall (t : nat) (di0 cx0 al0 : BV) (mem0 : Memo) (ad0 da0 : BV), da2 t di0 cx0 al0 mem0 ad0 da0 = da0.