aboutsummaryrefslogtreecommitdiffstats
path: root/src/hls
diff options
context:
space:
mode:
authorYann Herklotz <git@yannherklotz.com>2022-03-31 15:41:42 +0100
committerYann Herklotz <git@yannherklotz.com>2022-03-31 15:41:42 +0100
commitdc7eab1a1a7e7a12ff14fb9191c813a405303e4a (patch)
tree6dd781e24a2a260047a8fc9e0a177d1b81bc3b5c /src/hls
parent505044f22f904a606a1251d72def322512ca4789 (diff)
parent2e232deb0aed4af2448eb9f1031e8084181174b7 (diff)
downloadvericert-dc7eab1a1a7e7a12ff14fb9191c813a405303e4a.tar.gz
vericert-dc7eab1a1a7e7a12ff14fb9191c813a405303e4a.zip
Merge branch 'dev/scheduling'
Diffstat (limited to 'src/hls')
-rw-r--r--src/hls/Abstr.v208
-rw-r--r--src/hls/Array.v5
-rw-r--r--src/hls/AssocMap.v88
-rw-r--r--src/hls/FunctionalUnits.v101
-rw-r--r--src/hls/HTL.v104
-rw-r--r--src/hls/HTLPargen.v245
-rw-r--r--src/hls/HTLgen.v24
-rw-r--r--src/hls/HTLgenproof.v54
-rw-r--r--src/hls/HTLgenspec.v27
-rw-r--r--src/hls/IfConversion.v42
-rw-r--r--src/hls/Memorygen.v8
-rw-r--r--src/hls/Partition.ml14
-rw-r--r--src/hls/Pipeline.v3
-rw-r--r--src/hls/PipelineOp.v193
-rw-r--r--src/hls/Predicate.v628
-rw-r--r--src/hls/PrintAbstr.ml39
-rw-r--r--src/hls/PrintRTLBlockInstr.ml6
-rw-r--r--src/hls/PrintRTLParFU.ml120
-rw-r--r--src/hls/PrintVerilog.ml19
-rw-r--r--src/hls/RICtransf.v87
-rw-r--r--src/hls/RTLBlock.v102
-rw-r--r--src/hls/RTLBlockInstr.v309
-rw-r--r--src/hls/RTLBlockgen.v196
-rw-r--r--src/hls/RTLBlockgenproof.v170
-rw-r--r--src/hls/RTLPar.v53
-rw-r--r--src/hls/RTLParFU.v389
-rw-r--r--src/hls/RTLParFUgen.v177
-rw-r--r--src/hls/RTLPargen.v108
-rw-r--r--src/hls/RTLPargenproof.v32
-rw-r--r--src/hls/Sat.v2
-rw-r--r--src/hls/Schedule.ml104
-rw-r--r--src/hls/ValueInt.v42
-rw-r--r--src/hls/Verilog.v120
-rw-r--r--src/hls/Veriloggen.v32
-rw-r--r--src/hls/Veriloggenproof.v12
35 files changed, 2878 insertions, 985 deletions
diff --git a/src/hls/Abstr.v b/src/hls/Abstr.v
index abc4181..9d310fb 100644
--- a/src/hls/Abstr.v
+++ b/src/hls/Abstr.v
@@ -42,9 +42,9 @@ Require Import vericert.hls.Predicate.
Schedule Oracle
===============
-This oracle determines if a schedule was valid by performing symbolic execution on the input and
-output and showing that these behave the same. This acts on each basic block separately, as the
-rest of the functions should be equivalent.
+This oracle determines if a schedule was valid by performing symbolic execution
+on the input and output and showing that these behave the same. This acts on
+each basic block separately, as the rest of the functions should be equivalent.
|*)
Definition reg := positive.
@@ -55,8 +55,9 @@ Inductive resource : Set :=
| Mem : resource.
(*|
-The following defines quite a few equality comparisons automatically, however, these can be
-optimised heavily if written manually, as their proofs are not needed.
+The following defines quite a few equality comparisons automatically, however,
+these can be optimised heavily if written manually, as their proofs are not
+needed.
|*)
Lemma resource_eq : forall (r1 r2 : resource), {r1 = r2} + {r1 <> r2}.
@@ -180,9 +181,10 @@ Proof.
Defined.
(*|
-We then create equality lemmas for a resource and a module to index resources uniquely. The
-indexing is done by setting Mem to 1, whereas all other infinitely many registers will all be
-shifted right by 1. This means that they will never overlap.
+We then create equality lemmas for a resource and a module to index resources
+uniquely. The indexing is done by setting Mem to 1, whereas all other
+infinitely many registers will all be shifted right by 1. This means that they
+will never overlap.
|*)
Module R_indexed.
@@ -201,17 +203,19 @@ Module R_indexed.
End R_indexed.
(*|
-We can then create expressions that mimic the expressions defined in RTLBlock and RTLPar, which use
-expressions instead of registers as their inputs and outputs. This means that we can accumulate all
-the results of the operations as general expressions that will be present in those registers.
+We can then create expressions that mimic the expressions defined in RTLBlock
+and RTLPar, which use expressions instead of registers as their inputs and
+outputs. This means that we can accumulate all the results of the operations as
+general expressions that will be present in those registers.
- Ebase: the starting value of the register.
- Eop: Some arithmetic operation on a number of registers.
- Eload: A load from a memory location into a register.
- Estore: A store from a register to a memory location.
-Then, to make recursion over expressions easier, expression_list is also defined in the datatype, as
-that enables mutual recursive definitions over the datatypes.
+Then, to make recursion over expressions easier, expression_list is also defined
+in the datatype, as that enables mutual recursive definitions over the
+datatypes.
|*)
Inductive expression : Type :=
@@ -322,8 +326,8 @@ Definition predicated A := NE.non_empty (pred_op * A).
Definition pred_expr := predicated expression.
(*|
-Using IMap we can create a map from resources to any other type, as resources can be uniquely
-identified as positive numbers.
+Using ``IMap`` we can create a map from resources to any other type, as
+resources can be uniquely identified as positive numbers.
|*)
Module Rtree := ITree(R_indexed).
@@ -357,8 +361,9 @@ Definition eval_predf_opt pr p :=
match p with Some p' => eval_predf pr p' | None => true end.
(*|
-Finally we want to define the semantics of execution for the expressions with symbolic values, so
-the result of executing the expressions will be an expressions.
+Finally we want to define the semantics of execution for the expressions with
+symbolic values, so the result of executing the expressions will be an
+expressions.
|*)
Section SEMANTICS.
@@ -630,15 +635,6 @@ Definition encode_expression max pe h :=
(Pand (Por (Pnot p) (Pvar p')) p'', h'')
end.*)
-Fixpoint max_predicate (p: pred_op) : positive :=
- match p with
- | Plit (b, p) => p
- | Ptrue => 1
- | Pfalse => 1
- | Pand a b => Pos.max (max_predicate a) (max_predicate b)
- | Por a b => Pos.max (max_predicate a) (max_predicate b)
- end.
-
Fixpoint max_pred_expr (pe: pred_expr) : positive :=
match pe with
| NE.singleton (p, e) => max_predicate p
@@ -691,7 +687,7 @@ Inductive similar {A B} : @ctx A -> @ctx B -> Prop :=
Definition beq_pred_expr_once (pe1 pe2: pred_expr) : bool :=
match pe1, pe2 with
- (*| PEsingleton None e1, PEsingleton None e2 => beq_expression e1 e2
+ (* PEsingleton None e1, PEsingleton None e2 => beq_expression e1 e2
| PEsingleton (Some p1) e1, PEsingleton (Some p2) e2 =>
if beq_expression e1 e2
then match sat_pred_simple bound (Por (Pand p1 (Pnot p2)) (Pand p2 (Pnot p1))) with
@@ -714,48 +710,6 @@ Definition beq_pred_expr_once (pe1 pe2: pred_expr) : bool :=
equiv_check p1 p2
end.
-Definition forall_ptree {A:Type} (f:positive->A->bool) (m:Maps.PTree.t A) : bool :=
- Maps.PTree.fold (fun (res: bool) (i: positive) (x: A) => res && f i x) m true.
-
-Ltac boolInv :=
- match goal with
- | [ H: _ && _ = true |- _ ] =>
- destruct (andb_prop _ _ H); clear H; boolInv
- | [ H: proj_sumbool _ = true |- _ ] =>
- generalize (proj_sumbool_true _ H); clear H;
- let EQ := fresh in (intro EQ; try subst; boolInv)
- | _ =>
- idtac
- end.
-
-Remark ptree_forall:
- forall (A: Type) (f: positive -> A -> bool) (m: Maps.PTree.t A),
- Maps.PTree.fold (fun (res: bool) (i: positive) (x: A) => res && f i x) m true = true ->
- forall i x, Maps.PTree.get i m = Some x -> f i x = true.
-Proof.
- intros.
- set (f' := fun (res: bool) (i: positive) (x: A) => res && f i x).
- set (P := fun (m: Maps.PTree.t A) (res: bool) =>
- res = true -> Maps.PTree.get i m = Some x -> f i x = true).
- assert (P m true).
- rewrite <- H. fold f'. apply Maps.PTree_Properties.fold_rec.
- unfold P; intros. rewrite <- H1 in H4. auto.
- red; intros. now rewrite Maps.PTree.gempty in H2.
- unfold P; intros. unfold f' in H4. boolInv.
- rewrite Maps.PTree.gsspec in H5. destruct (peq i k).
- subst. inv H5. auto.
- apply H3; auto.
- red in H1. auto.
-Qed.
-
-Lemma forall_ptree_true:
- forall (A: Type) (f: positive -> A -> bool) (m: Maps.PTree.t A),
- forall_ptree f m = true ->
- forall i x, Maps.PTree.get i m = Some x -> f i x = true.
-Proof.
- apply ptree_forall.
-Qed.
-
Definition tree_equiv_check_el (np2: PTree.t pred_op) (n: positive) (p: pred_op): bool :=
match np2 ! n with
| Some p' => equiv_check p p'
@@ -1386,48 +1340,88 @@ Proof.
end; discriminate.
Qed.
-Fixpoint beq2 {A B : Type} (beqA : A -> B -> bool) (m1 : PTree.t A) (m2 : PTree.t B) {struct m1} : bool :=
- match m1, m2 with
- | PTree.Leaf, _ => PTree.bempty m2
- | _, PTree.Leaf => PTree.bempty m1
- | PTree.Node l1 o1 r1, PTree.Node l2 o2 r2 =>
+Section BOOLEAN_EQUALITY.
+
+ Context {A B: Type}.
+ Context (beqA: A -> B -> bool).
+
+ Fixpoint beq2' (m1: PTree.tree' A) (m2: PTree.tree' B) {struct m1} : bool :=
+ match m1, m2 with
+ | PTree.Node001 r1, PTree.Node001 r2 => beq2' r1 r2
+ | PTree.Node010 x1, PTree.Node010 x2 => beqA x1 x2
+ | PTree.Node011 x1 r1, PTree.Node011 x2 r2 => beqA x1 x2 && beq2' r1 r2
+ | PTree.Node100 l1, PTree.Node100 l2 => beq2' l1 l2
+ | PTree.Node101 l1 r1, PTree.Node101 l2 r2 => beq2' l1 l2 && beq2' r1 r2
+ | PTree.Node110 l1 x1, PTree.Node110 l2 x2 => beqA x1 x2 && beq2' l1 l2
+ | PTree.Node111 l1 x1 r1, PTree.Node111 l2 x2 r2 => beqA x1 x2 && beq2' l1 l2 && beq2' r1 r2
+ | _, _ => false
+ end.
+
+ Definition beq2 (m1: PTree.t A) (m2 : PTree.t B) : bool :=
+ match m1, m2 with
+ | PTree.Empty, PTree.Empty => true
+ | PTree.Nodes m1', PTree.Nodes m2' => beq2' m1' m2'
+ | _, _ => false
+ end.
+
+ Let beq2_optA (o1: option A) (o2: option B) : bool :=
match o1, o2 with
| None, None => true
- | Some y1, Some y2 => beqA y1 y2
+ | Some a1, Some a2 => beqA a1 a2
| _, _ => false
- end
- && beq2 beqA l1 l2 && beq2 beqA r1 r2
- end.
+ end.
-Lemma beq2_correct:
- forall A B beqA m1 m2,
- @beq2 A B beqA m1 m2 = true <->
- (forall (x: PTree.elt),
- match PTree.get x m1, PTree.get x m2 with
- | None, None => True
- | Some y1, Some y2 => beqA y1 y2 = true
- | _, _ => False
- end).
-Proof.
- induction m1; intros.
- - simpl. rewrite PTree.bempty_correct. split; intros.
- rewrite PTree.gleaf. rewrite H. auto.
- generalize (H x). rewrite PTree.gleaf. destruct (PTree.get x m2); tauto.
- - destruct m2.
- + unfold beq2. rewrite PTree.bempty_correct. split; intros.
- rewrite H. rewrite PTree.gleaf. auto.
- generalize (H x). rewrite PTree.gleaf.
- destruct (PTree.get x (PTree.Node m1_1 o m1_2)); tauto.
- + simpl. split; intros.
- * destruct (andb_prop _ _ H). destruct (andb_prop _ _ H0).
- rewrite IHm1_1 in H3. rewrite IHm1_2 in H1.
- destruct x; simpl. apply H1. apply H3.
- destruct o; destruct o0; auto || congruence.
- * apply andb_true_intro. split. apply andb_true_intro. split.
- generalize (H xH); simpl. destruct o; destruct o0; tauto.
- apply IHm1_1. intros; apply (H (xO x)).
- apply IHm1_2. intros; apply (H (xI x)).
-Qed.
+ Lemma beq_correct_bool:
+ forall m1 m2,
+ beq2 m1 m2 = true <-> (forall x, beq2_optA (m1 ! x) (m2 ! x) = true).
+ Proof.
+ Local Transparent PTree.Node.
+ assert (beq_NN: forall l1 o1 r1 l2 o2 r2,
+ PTree.not_trivially_empty l1 o1 r1 ->
+ PTree.not_trivially_empty l2 o2 r2 ->
+ beq2 (PTree.Node l1 o1 r1) (PTree.Node l2 o2 r2) =
+ beq2 l1 l2 && beq2_optA o1 o2 && beq2 r1 r2).
+ { intros.
+ destruct l1, o1, r1; try contradiction; destruct l2, o2, r2; try contradiction;
+ simpl; rewrite ? andb_true_r, ? andb_false_r; auto.
+ rewrite andb_comm; auto.
+ f_equal; rewrite andb_comm; auto. }
+ induction m1 using PTree.tree_ind; [|induction m2 using PTree.tree_ind].
+ - intros. simpl; split; intros.
+ + destruct m2; try discriminate. simpl; auto.
+ + replace m2 with (@PTree.Empty B); auto. apply PTree.extensionality; intros x.
+ specialize (H x). destruct (m2 ! x); simpl; easy.
+ - split; intros.
+ + destruct (PTree.Node l o r); try discriminate. simpl; auto.
+ + replace (PTree.Node l o r) with (@PTree.Empty A); auto. apply PTree.extensionality; intros x.
+ specialize (H0 x). destruct ((PTree.Node l o r) ! x); simpl in *; easy.
+ - rewrite beq_NN by auto. split; intros.
+ + InvBooleans. rewrite ! PTree.gNode. destruct x.
+ * apply IHm0; auto.
+ * apply IHm1; auto.
+ * auto.
+ + apply andb_true_intro; split; [apply andb_true_intro; split|].
+ * apply IHm1. intros. specialize (H1 (xO x)); rewrite ! PTree.gNode in H1; auto.
+ * specialize (H1 xH); rewrite ! PTree.gNode in H1; auto.
+ * apply IHm0. intros. specialize (H1 (xI x)); rewrite ! PTree.gNode in H1; auto.
+ Qed.
+
+ Theorem beq2_correct:
+ forall m1 m2,
+ beq2 m1 m2 = true <->
+ (forall (x: PTree.elt),
+ match m1 ! x, m2 ! x with
+ | None, None => True
+ | Some y1, Some y2 => beqA y1 y2 = true
+ | _, _ => False
+ end).
+ Proof.
+ intros. rewrite beq_correct_bool. unfold beq2_optA. split; intros.
+ - specialize (H x). destruct (m1 ! x), (m2 ! x); intuition congruence.
+ - specialize (H x). destruct (m1 ! x), (m2 ! x); intuition auto.
+ Qed.
+
+End BOOLEAN_EQUALITY.
Lemma map1:
forall w dst dst',
diff --git a/src/hls/Array.v b/src/hls/Array.v
index 0f5ae02..de74611 100644
--- a/src/hls/Array.v
+++ b/src/hls/Array.v
@@ -190,7 +190,10 @@ Proof.
auto using nth_error_nth.
Qed.
-(** Tail recursive version of standard library function. *)
+(*|
+Tail recursive version of standard library function.
+|*)
+
Fixpoint list_repeat' {A : Type} (acc : list A) (a : A) (n : nat) : list A :=
match n with
| O => acc
diff --git a/src/hls/AssocMap.v b/src/hls/AssocMap.v
index 8dbc6b2..ee39e8e 100644
--- a/src/hls/AssocMap.v
+++ b/src/hls/AssocMap.v
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
* 2020 James Pollard <j@mes.dev>
*
* This program is free software: you can redistribute it and/or modify
@@ -42,63 +42,75 @@ Module AssocMapExt.
| Some v => v
end.
- Fixpoint merge (m1 m2 : t A) : t A :=
- match m1, m2 with
- | Node l1 (Some a) r1, Node l2 _ r2 => Node (merge l1 l2) (Some a) (merge r1 r2)
- | Node l1 None r1, Node l2 o r2 => Node (merge l1 l2) o (merge r1 r2)
- | Leaf, _ => m2
- | _, _ => m1
+ Definition merge_atom (new : option A) (old : option A) : option A :=
+ match new, old with
+ | Some _, _ => new
+ | _, _ => old
end.
+ Definition merge (m1 m2 : t A) : t A :=
+ PTree.combine merge_atom m1 m2.
+
Lemma merge_base_1 :
- forall am,
- merge (empty A) am = am.
- Proof. auto. Qed.
+ forall am x,
+ (merge (empty A) am) ! x = am ! x.
+ Proof using.
+ unfold merge; intros.
+ rewrite PTree.gcombine; eauto.
+ Qed.
Lemma merge_base_2 :
- forall am,
- merge am (empty A) = am.
- Proof.
- unfold merge.
- destruct am; trivial.
- destruct o; trivial.
+ forall am x,
+ (merge am (empty A)) ! x = am ! x.
+ Proof using.
+ unfold merge; intros.
+ rewrite PTree.gcombine; eauto.
+ cbv [merge_atom]. destruct_match; crush.
Qed.
Lemma merge_add_assoc :
- forall r am am' v,
- merge (set r v am) am' = set r v (merge am am').
- Proof.
- induction r; intros; destruct am; destruct am'; try (destruct o); simpl;
- try rewrite IHr; try reflexivity.
+ forall r am am' v x,
+ (merge (set r v am) am') ! x = (set r v (merge am am')) ! x.
+ Proof using.
+ unfold merge. intros; rewrite PTree.gcombine by auto.
+ unfold merge_atom. destruct_match.
+ destruct (peq r x); subst.
+ rewrite PTree.gss in Heqo. inv Heqo. rewrite PTree.gss. auto.
+ rewrite PTree.gso in Heqo by auto. rewrite PTree.gso by auto.
+ rewrite PTree.gcombine by auto. rewrite Heqo. auto.
+ destruct (peq r x); subst.
+ rewrite PTree.gss in Heqo. inv Heqo.
+ rewrite PTree.gso in Heqo by auto. rewrite PTree.gso by auto.
+ rewrite PTree.gcombine by auto. rewrite Heqo. auto.
Qed.
Lemma merge_correct_1 :
forall am bm k v,
- get k am = Some v ->
- get k (merge am bm) = Some v.
- Proof.
- induction am; intros; destruct k; destruct bm; try (destruct o); simpl;
- try rewrite gempty in H; try discriminate; try assumption; auto.
+ am ! k = Some v ->
+ (merge am bm) ! k = Some v.
+ Proof using.
+ unfold merge; intros. rewrite PTree.gcombine by auto.
+ rewrite H; auto.
Qed.
Lemma merge_correct_2 :
forall am bm k v,
- get k am = None ->
- get k bm = Some v ->
- get k (merge am bm) = Some v.
- Proof.
- induction am; intros; destruct k; destruct bm; try (destruct o); simpl;
- try rewrite gempty in H; try discriminate; try assumption; auto.
+ am ! k = None ->
+ bm ! k = Some v ->
+ (merge am bm) ! k = Some v.
+ Proof using.
+ unfold merge; intros. rewrite PTree.gcombine by auto.
+ rewrite H. rewrite H0. auto.
Qed.
Lemma merge_correct_3 :
forall am bm k,
- get k am = None ->
- get k bm = None ->
- get k (merge am bm) = None.
- Proof.
- induction am; intros; destruct k; destruct bm; try (destruct o); simpl;
- try rewrite gempty in H; try discriminate; try assumption; auto.
+ am ! k = None ->
+ bm ! k = None ->
+ (merge am bm) ! k = None.
+ Proof using.
+ unfold merge; intros. rewrite PTree.gcombine by auto.
+ rewrite H. rewrite H0. auto.
Qed.
Definition merge_fold (am bm : t A) : t A :=
diff --git a/src/hls/FunctionalUnits.v b/src/hls/FunctionalUnits.v
index e94b8e8..dcbe22f 100644
--- a/src/hls/FunctionalUnits.v
+++ b/src/hls/FunctionalUnits.v
@@ -52,13 +52,11 @@ Record ram := mk_ram {
ram_wr_en: reg;
ram_d_in: reg;
ram_d_out: reg;
- ram_ordering: (ram_addr < ram_en
- /\ ram_en < ram_d_in
- /\ ram_d_in < ram_d_out
- /\ ram_d_out < ram_wr_en
- /\ ram_wr_en < ram_u_en)
}.
+Definition all_ram_regs r :=
+ ram_mem r::ram_en r::ram_u_en r::ram_addr r::ram_wr_en r::ram_d_in r::ram_d_out r::nil.
+
Inductive funct_unit: Type :=
| SignedDiv: divider true -> funct_unit
| UnsignedDiv: divider false -> funct_unit
@@ -77,6 +75,80 @@ Record resources := mk_resources {
res_arch: arch;
}.
+Definition index_div {b:bool} r (d: divider b) :=
+ match r with
+ | 1 => div_numer d
+ | 2 => div_denom d
+ | 3 => div_quot d
+ | _ => div_rem d
+ end.
+
+Definition index_ram r (d: ram) :=
+ match r with
+ | 1 => ram_mem d
+ | 2 => ram_en d
+ | 3 => ram_u_en d
+ | 4 => ram_addr d
+ | 5 => ram_wr_en d
+ | 6 => ram_d_in d
+ | _ => ram_d_out d
+ end.
+
+Definition index_res u r res :=
+ match PTree.get u res with
+ | Some (SignedDiv d) => Some (index_div r d)
+ | Some (UnsignedDiv d) => Some (index_div r d)
+ | Some (Ram d) => Some (index_ram r d)
+ | None => None
+ end.
+
+Definition get_ram n res: option (positive * ram) :=
+ match nth_error (arch_ram (res_arch res)) n with
+ | Some ri =>
+ match PTree.get ri (res_funct_units res) with
+ | Some (Ram r) => Some (ri, r)
+ | _ => None
+ end
+ | None => None
+ end.
+
+Definition get_div n res :=
+ match nth_error (arch_div (res_arch res)) n with
+ | Some ri =>
+ match PTree.get ri (res_funct_units res) with
+ | Some (UnsignedDiv d) => Some (ri, d)
+ | _ => None
+ end
+ | None => None
+ end.
+
+Definition get_sdiv n res :=
+ match nth_error (arch_sdiv (res_arch res)) n with
+ | Some ri =>
+ match PTree.get ri (res_funct_units res) with
+ | Some (SignedDiv d) => Some (ri, d)
+ | _ => None
+ end
+ | None => None
+ end.
+
+Definition set_res fu res :=
+ let max := ((fold_left Pos.max ((arch_sdiv (res_arch res))
+ ++ (arch_div (res_arch res))
+ ++ (arch_ram (res_arch res))) 1) + 1)%positive in
+ let nt := PTree.set max fu (res_funct_units res) in
+ match fu with
+ | UnsignedDiv _ => mk_resources nt (mk_arch (max :: arch_div (res_arch res))
+ (arch_sdiv (res_arch res))
+ (arch_ram (res_arch res)))
+ | SignedDiv _ => mk_resources nt (mk_arch (arch_div (res_arch res))
+ (max :: arch_sdiv (res_arch res))
+ (arch_ram (res_arch res)))
+ | Ram _ => mk_resources nt (mk_arch (arch_div (res_arch res))
+ (arch_sdiv (res_arch res))
+ (max :: arch_ram (res_arch res)))
+ end.
+
Definition initial_funct_units: funct_units := PTree.empty _.
Definition initial_arch := mk_arch nil nil nil.
@@ -90,3 +162,22 @@ Definition funct_unit_stages (f: funct_unit) : positive :=
| UnsignedDiv d => div_stages d
| _ => 1
end.
+
+Definition max_reg_ram r :=
+ fold_right Pos.max 1 (ram_mem r::ram_en r::ram_u_en r::ram_addr r
+ ::ram_wr_en r::ram_d_in r::ram_d_out r::nil).
+
+Definition max_reg_divider {b: bool} (d: divider b) :=
+ fold_right Pos.max 1 (div_numer d::div_denom d::div_quot d::div_rem d::nil).
+
+Definition max_reg_fu fu :=
+ match fu with
+ | SignedDiv d | UnsignedDiv d => max_reg_divider d
+ | Ram r => max_reg_ram r
+ end.
+
+Definition max_reg_funct_units r :=
+ PTree.fold (fun m _ a => Pos.max m (max_reg_fu a)) r 1.
+
+Definition max_reg_resources r :=
+ max_reg_funct_units r.(res_funct_units).
diff --git a/src/hls/HTL.v b/src/hls/HTL.v
index 8cebbfd..f3af3d8 100644
--- a/src/hls/HTL.v
+++ b/src/hls/HTL.v
@@ -28,18 +28,21 @@ Require Import compcert.lib.Integers.
Require Import compcert.lib.Maps.
Require Import vericert.common.Vericertlib.
-Require Import vericert.hls.ValueInt.
-Require Import vericert.hls.AssocMap.
Require Import vericert.hls.Array.
+Require Import vericert.hls.FunctionalUnits.
Require vericert.hls.Verilog.
+Require Import AssocMap.
+Require Import ValueInt.
Local Open Scope positive.
-(** The purpose of the hardware transfer language (HTL) is to create a more
+(*|
+The purpose of the hardware transfer language (HTL) is to create a more
hardware-like layout that is still similar to the register transfer language
(RTL) that it came from. The main change is that function calls become module
instantiations and that we now describe a state machine instead of a
-control-flow graph. *)
+control-flow graph.
+|*)
Local Open Scope assocmap.
@@ -54,24 +57,6 @@ Definition map_well_formed {A : Type} (m : PTree.t A) : Prop :=
In p0 (map fst (Maps.PTree.elements m)) ->
(Z.pos p0 <= Integers.Int.max_unsigned)%Z.
-Record ram := mk_ram {
- ram_size: nat;
- ram_mem: reg;
- ram_en: reg;
- ram_u_en: reg;
- ram_addr: reg;
- ram_wr_en: reg;
- ram_d_in: reg;
- ram_d_out: reg;
- ram_ordering: (ram_addr < ram_en
- /\ ram_en < ram_d_in
- /\ ram_d_in < ram_d_out
- /\ ram_d_out < ram_wr_en
- /\ ram_wr_en < ram_u_en)
-}.
-
-Definition module_ordering a b c d e f g := a < b < c /\ c < d < e /\ e < f < g.
-
Record module: Type :=
mkmodule {
mod_params : list reg;
@@ -79,8 +64,6 @@ Record module: Type :=
mod_controllogic : controllogic;
mod_entrypoint : node;
mod_st : reg;
- mod_stk : reg;
- mod_stk_len : nat;
mod_finish : reg;
mod_return : reg;
mod_start : reg;
@@ -88,11 +71,7 @@ Record module: Type :=
mod_clk : reg;
mod_scldecls : AssocMap.t (option Verilog.io * Verilog.scl_decl);
mod_arrdecls : AssocMap.t (option Verilog.io * Verilog.arr_decl);
- mod_ram : option ram;
- mod_wf : map_well_formed mod_controllogic /\ map_well_formed mod_datapath;
- mod_ordering_wf : module_ordering mod_st mod_finish mod_return mod_stk mod_start mod_reset mod_clk;
- mod_ram_wf : forall r', mod_ram = Some r' -> mod_clk < ram_addr r';
- mod_params_wf : Forall (Pos.gt mod_st) mod_params;
+ mod_ram : ram;
}.
Definition fundef := AST.fundef module.
@@ -106,9 +85,12 @@ Fixpoint init_regs (vl : list value) (rl : list reg) {struct rl} :=
end.
Definition empty_stack (m : module) : Verilog.assocmap_arr :=
- (AssocMap.set m.(mod_stk) (Array.arr_repeat None m.(mod_stk_len)) (AssocMap.empty Verilog.arr)).
+ (AssocMap.set m.(mod_ram).(ram_mem) (Array.arr_repeat None m.(mod_ram).(ram_size)) (AssocMap.empty Verilog.arr)).
-(** * Operational Semantics *)
+(*|
+Operational Semantics
+=====================
+|*)
Definition genv := Globalenvs.Genv.t fundef unit.
@@ -137,13 +119,13 @@ Inductive state : Type :=
(args : list value), state.
Inductive exec_ram:
- Verilog.reg_associations -> Verilog.arr_associations -> option ram ->
+ Verilog.reg_associations -> Verilog.arr_associations -> ram ->
Verilog.reg_associations -> Verilog.arr_associations -> Prop :=
| exec_ram_Some_idle:
forall ra ar r,
Int.eq (Verilog.assoc_blocking ra)#(ram_en r, 32)
(Verilog.assoc_blocking ra)#(ram_u_en r, 32) = true ->
- exec_ram ra ar (Some r) ra ar
+ exec_ram ra ar r ra ar
| exec_ram_Some_write:
forall ra ar r d_in addr en wr_en u_en,
Int.eq en u_en = false ->
@@ -153,7 +135,7 @@ Inductive exec_ram:
(Verilog.assoc_blocking ra)!(ram_wr_en r) = Some wr_en ->
(Verilog.assoc_blocking ra)!(ram_d_in r) = Some d_in ->
(Verilog.assoc_blocking ra)!(ram_addr r) = Some addr ->
- exec_ram ra ar (Some r) (Verilog.nonblock_reg (ram_en r) ra u_en)
+ exec_ram ra ar r (Verilog.nonblock_reg (ram_en r) ra u_en)
(Verilog.nonblock_arr (ram_mem r) (valueToNat addr) ar d_in)
| exec_ram_Some_read:
forall ra ar r addr v_d_out en u_en,
@@ -164,11 +146,8 @@ Inductive exec_ram:
(Verilog.assoc_blocking ra)!(ram_addr r) = Some addr ->
Verilog.arr_assocmap_lookup (Verilog.assoc_blocking ar)
(ram_mem r) (valueToNat addr) = Some v_d_out ->
- exec_ram ra ar (Some r) (Verilog.nonblock_reg (ram_en r)
- (Verilog.nonblock_reg (ram_d_out r) ra v_d_out) u_en) ar
-| exec_ram_None:
- forall r a,
- exec_ram r a None r a.
+ exec_ram ra ar r (Verilog.nonblock_reg (ram_en r)
+ (Verilog.nonblock_reg (ram_d_out r) ra v_d_out) u_en) ar.
Inductive step : genv -> state -> Events.trace -> state -> Prop :=
| step_module :
@@ -246,6 +225,10 @@ Definition semantics (m : program) :=
Smallstep.Semantics step (initial_state m) final_state
(Globalenvs.Genv.globalenv m).
+Definition all_module_regs m :=
+ all_ram_regs (mod_ram m) ++
+ (mod_st m::mod_finish m::mod_return m::mod_start m::mod_reset m::mod_clk m::nil).
+
Definition max_pc_function (m: module) :=
List.fold_left Pos.max (List.map fst (PTree.elements m.(mod_controllogic))) 1.
@@ -266,17 +249,20 @@ Definition max_reg_ram r :=
(Pos.max (ram_d_out ram) (ram_u_en ram)))))))
end.
-Definition max_reg_module m :=
+Definition max_reg_body m :=
Pos.max (max_list (mod_params m))
- (Pos.max (max_stmnt_tree (mod_datapath m))
- (Pos.max (max_stmnt_tree (mod_controllogic m))
- (Pos.max (mod_st m)
- (Pos.max (mod_stk m)
- (Pos.max (mod_finish m)
- (Pos.max (mod_return m)
- (Pos.max (mod_start m)
- (Pos.max (mod_reset m)
- (Pos.max (mod_clk m) (max_reg_ram (mod_ram m))))))))))).
+ (Pos.max (max_stmnt_tree (mod_datapath m))
+ (max_stmnt_tree (mod_controllogic m))).
+
+Definition max_reg_module m :=
+ Pos.max (max_reg_body m) (max_list (all_module_regs m)).
+
+Record wf_htl_module m :=
+ mk_wf_htl_module {
+ mod_wf : map_well_formed (mod_controllogic m) /\ map_well_formed (mod_datapath m);
+ mod_ordering_wf : list_norepet (all_module_regs m);
+ mod_gt : Forall (Pos.lt (max_reg_body m)) (all_module_regs m);
+ }.
Lemma max_fold_lt :
forall m l n, m <= n -> m <= (fold_left Pos.max l n).
@@ -333,12 +319,16 @@ Proof. intros. apply max_reg_stmnt_le_stmnt_tree in H; lia. Qed.
Lemma max_stmnt_lt_module :
forall m d i,
+ wf_htl_module m ->
(mod_controllogic m) ! i = Some d \/ (mod_datapath m) ! i = Some d ->
Verilog.max_reg_stmnt d < max_reg_module m + 1.
Proof.
- inversion 1 as [ Hv | Hv ]; unfold max_reg_module;
- apply max_reg_stmnt_le_stmnt_tree in Hv; lia.
-Qed.
+ intros. apply mod_gt in H.
+ unfold Pos.lt, max_reg_body, max_reg_module, max_list, all_module_regs, all_ram_regs in *.
+ simplify.
+ repeat match goal with H: Forall _ _ |- _ => inv H end.
+ inversion H0 as [Hv | Hv]; apply max_reg_stmnt_le_stmnt_tree in Hv.
+ Admitted.
Lemma max_list_correct l st : st > max_list l -> Forall (Pos.gt st) l.
Proof. induction l; crush; constructor; [|apply IHl]; lia. Qed.
@@ -352,3 +342,13 @@ Definition max_list_dec (l: list reg) (st: reg) : {Forall (Pos.gt st) l} + {True
); auto.
apply max_list_correct. apply Pos.ltb_lt in e. lia.
Qed.
+
+Variant wf_htl_fundef: fundef -> Prop :=
+ | wf_htl_fundef_external: forall ef,
+ wf_htl_fundef (AST.External ef)
+ | wf_htl_function_internal: forall f,
+ wf_htl_module f ->
+ wf_htl_fundef (AST.Internal f).
+
+Definition wf_htl_program (p: program) : Prop :=
+ forall f id, In (id, AST.Gfun f) (AST.prog_defs p) -> wf_htl_fundef f.
diff --git a/src/hls/HTLPargen.v b/src/hls/HTLPargen.v
index b0815b7..8960ef9 100644
--- a/src/hls/HTLPargen.v
+++ b/src/hls/HTLPargen.v
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2021 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,10 +27,12 @@ Require Import compcert.lib.Maps.
Require Import vericert.common.Statemonad.
Require Import vericert.common.Vericertlib.
Require Import vericert.hls.AssocMap.
+Require Import vericert.hls.FunctionalUnits.
Require Import vericert.hls.HTL.
Require Import vericert.hls.Predicate.
Require Import vericert.hls.RTLBlockInstr.
-Require Import vericert.hls.RTLPar.
+Require Import vericert.hls.RTLParFU.
+Require Import vericert.hls.FunctionalUnits.
Require Import vericert.hls.ValueInt.
Require Import vericert.hls.Verilog.
@@ -143,6 +145,30 @@ Definition declare_reg (i : option io) (r : reg) (sz : nat) : mon unit :=
s.(st_controllogic))
(declare_reg_state_incr i s r sz).
+Lemma declare_arr_state_incr :
+ forall i s r sz ln,
+ st_incr s
+ (mkstate
+ s.(st_st)
+ s.(st_freshreg)
+ s.(st_freshstate)
+ s.(st_scldecls)
+ (AssocMap.set r (i, VArray sz ln) s.(st_arrdecls))
+ s.(st_datapath)
+ s.(st_controllogic)).
+Proof. Admitted.
+
+Definition declare_arr (i : option io) (r : reg) (sz : nat) (ln : nat) : mon unit :=
+ fun s => OK tt (mkstate
+ s.(st_st)
+ s.(st_freshreg)
+ s.(st_freshstate)
+ s.(st_scldecls)
+ (AssocMap.set r (i, VArray sz ln) s.(st_arrdecls))
+ s.(st_datapath)
+ s.(st_controllogic))
+ (declare_arr_state_incr i s r sz ln).
+
Lemma add_instr_state_incr :
forall s n n' st,
(st_controllogic s)!n = None ->
@@ -328,6 +354,30 @@ Definition check_address_parameter_signed (p : Z) : bool :=
Definition check_address_parameter_unsigned (p : Z) : bool :=
Z.leb p Integers.Ptrofs.max_unsigned.
+Lemma create_reg_state_incr:
+ forall s sz i,
+ st_incr s (mkstate
+ s.(st_st)
+ (Pos.succ (st_freshreg s))
+ (st_freshstate s)
+ (AssocMap.set s.(st_freshreg) (i, VScalar sz) s.(st_scldecls))
+ s.(st_arrdecls)
+ (st_datapath s)
+ (st_controllogic s)).
+Proof. constructor; simpl; auto with htlh. Qed.
+
+Definition create_reg (i : option io) (sz : nat) : mon reg :=
+ fun s => let r := s.(st_freshreg) in
+ OK r (mkstate
+ s.(st_st)
+ (Pos.succ r)
+ (st_freshstate s)
+ (AssocMap.set s.(st_freshreg) (i, VScalar sz) s.(st_scldecls))
+ (st_arrdecls s)
+ (st_datapath s)
+ (st_controllogic s))
+ (create_reg_state_incr s sz i).
+
Definition translate_eff_addressing (a: Op.addressing) (args: list reg)
: mon expr :=
match a, args with (* TODO: We should be more methodical here; what are the possibilities?*)
@@ -355,7 +405,10 @@ Definition translate_eff_addressing (a: Op.addressing) (args: list reg)
| _, _ => error (Errors.msg "HTLPargen: translate_eff_addressing unsuported addressing")
end.
-(** Translate an instruction to a statement. FIX mulhs mulhu *)
+(*|
+Translate an instruction to a statement. FIX mulhs mulhu
+|*)
+
Definition translate_instr (op : Op.operation) (args : list reg) : mon expr :=
match op, args with
| Op.Omove, r::nil => ret (Vvar r)
@@ -432,28 +485,6 @@ Definition add_branch_instr (e: expr) (n n1 n2: node) : mon unit :=
| _ => Error (Errors.msg "Htlgen: add_branch_instr")
end.
-Definition translate_arr_access (mem : AST.memory_chunk) (addr : Op.addressing)
- (args : list reg) (stack : reg) : mon expr :=
- match mem, addr, args with (* TODO: We should be more methodical here; what are the possibilities?*)
- | Mint32, Op.Aindexed off, r1::nil =>
- if (check_address_parameter_signed off)
- then ret (Vvari stack (Vbinop Vdivu (boplitz Vadd r1 off) (Vlit (ZToValue 4))))
- else error (Errors.msg "HTLgen: translate_arr_access address out of bounds")
- | Mint32, Op.Aindexed2scaled scale offset, r1::r2::nil => (* Typical for dynamic array addressing *)
- if (check_address_parameter_signed scale) && (check_address_parameter_signed offset)
- then ret (Vvari stack
- (Vbinop Vdivu
- (Vbinop Vadd (boplitz Vadd r1 offset) (boplitz Vmul r2 scale))
- (Vlit (ZToValue 4))))
- else error (Errors.msg "HTLgen: translate_arr_access address out of bounds")
- | Mint32, Op.Ainstack a, nil => (* We need to be sure that the base address is aligned *)
- let a := Integers.Ptrofs.unsigned a in
- if (check_address_parameter_unsigned a)
- then ret (Vvari stack (Vlit (ZToValue (a / 4))))
- else error (Errors.msg "HTLgen: eff_addressing out of bounds stack offset")
- | _, _, _ => error (Errors.msg "HTLgen: translate_arr_access unsuported addressing")
- end.
-
Fixpoint enumerate (i : nat) (ns : list node) {struct ns} : list (nat * node) :=
match ns with
| n :: ns' => (i, n) :: enumerate (i+1) ns'
@@ -469,30 +500,6 @@ Definition tbl_to_case_expr (st : reg) (ns : list node) : list (expr * stmnt) :=
Definition stack_correct (sz : Z) : bool :=
(0 <=? sz) && (sz <? Integers.Ptrofs.modulus) && (Z.modulo sz 4 =? 0).
-Lemma create_reg_state_incr:
- forall s sz i,
- st_incr s (mkstate
- s.(st_st)
- (Pos.succ (st_freshreg s))
- (st_freshstate s)
- (AssocMap.set s.(st_freshreg) (i, VScalar sz) s.(st_scldecls))
- s.(st_arrdecls)
- (st_datapath s)
- (st_controllogic s)).
-Proof. constructor; simpl; auto with htlh. Qed.
-
-Definition create_reg (i : option io) (sz : nat) : mon reg :=
- fun s => let r := s.(st_freshreg) in
- OK r (mkstate
- s.(st_st)
- (Pos.succ r)
- (st_freshstate s)
- (AssocMap.set s.(st_freshreg) (i, VScalar sz) s.(st_scldecls))
- (st_arrdecls s)
- (st_datapath s)
- (st_controllogic s))
- (create_reg_state_incr s sz i).
-
Lemma create_arr_state_incr:
forall s sz ln i,
st_incr s (mkstate
@@ -678,23 +685,18 @@ Definition translate_predicate (a : assignment)
ret (a dst (Vternary (pred_expr preg pos) e dst))
end.
-Definition translate_inst a (fin rtrn stack preg : reg) (n : node) (i : instr)
+Definition translate_inst a (fin rtrn preg : reg) (n : node) (i : instr)
: mon stmnt :=
match i with
- | RBnop =>
+ | FUnop =>
ret Vskip
- | RBop p op args dst =>
+ | FUop p op args dst =>
do instr <- translate_instr op args;
do _ <- declare_reg None dst 32;
translate_predicate a preg p (Vvar dst) instr
- | RBload p chunk addr args dst =>
- do src <- translate_arr_access chunk addr args stack;
- do _ <- declare_reg None dst 32;
- translate_predicate a preg p (Vvar dst) src
- | RBstore p chunk addr args src =>
- do dst <- translate_arr_access chunk addr args stack;
- translate_predicate a preg p dst (Vvar src)
- | RBsetpred _ c args p =>
+ | FUread p1 p2 r => ret Vskip
+ | FUwrite p1 p2 r => ret Vskip
+ | FUsetpred _ c args p =>
do cond <- translate_condition c args;
ret (a (pred_expr preg (Plit (true, p))) cond)
end.
@@ -724,28 +726,28 @@ Definition create_new_state (p: node): mon node :=
s.(st_controllogic))
(create_new_state_state_incr s p).
-Definition translate_inst_list (fin rtrn stack preg: reg) (ni : node * node * list (list instr)) :=
+Definition translate_inst_list (fin rtrn preg: reg) (ni : node * node * list (list instr)) :=
match ni with
| (n, p, li) =>
do _ <- collectlist
(fun l =>
- do stmnt <- translate_inst Vblock fin rtrn stack preg n l;
+ do stmnt <- translate_inst Vblock fin rtrn preg n l;
add_data_instr n stmnt) (concat li);
do st <- get;
add_control_instr n (state_goto st.(st_st) p)
end.
-Fixpoint translate_cfi' (fin rtrn stack preg: reg) (cfi: cf_instr)
+Fixpoint translate_cfi' (fin rtrn preg: reg) (cfi: cf_instr)
: mon (stmnt * stmnt) :=
match cfi with
- | RBgoto n' =>
+ | FUgoto n' =>
do st <- get;
ret (Vskip, state_goto st.(st_st) n')
- | RBcond c args n1 n2 =>
+ | FUcond c args n1 n2 =>
do st <- get;
do e <- translate_condition c args;
ret (Vskip, state_cond st.(st_st) e n1 n2)
- | RBreturn r =>
+ | FUreturn r =>
match r with
| Some r' =>
ret ((Vseq (block fin (Vlit (ZToValue 1%Z))) (block rtrn (Vvar r'))),
@@ -754,41 +756,41 @@ Fixpoint translate_cfi' (fin rtrn stack preg: reg) (cfi: cf_instr)
ret ((Vseq (block fin (Vlit (ZToValue 1%Z))) (block rtrn (Vlit (ZToValue 0%Z)))),
Vskip)
end
- | RBpred_cf p c1 c2 =>
- do (tc1s, tc1c) <- translate_cfi' fin rtrn stack preg c1;
- do (tc2s, tc2c) <- translate_cfi' fin rtrn stack preg c2;
+ | FUpred_cf p c1 c2 =>
+ do (tc1s, tc1c) <- translate_cfi' fin rtrn preg c1;
+ do (tc2s, tc2c) <- translate_cfi' fin rtrn preg c2;
ret ((Vcond (pred_expr preg p) tc1s tc2s), (Vcond (pred_expr preg p) tc1c tc2c))
- | RBjumptable r tbl =>
+ | FUjumptable r tbl =>
do s <- get;
ret (Vskip, Vcase (Vvar r) (list_to_stmnt (tbl_to_case_expr s.(st_st) tbl)) (Some Vskip))
- | RBcall sig ri rl r n =>
+ | FUcall sig ri rl r n =>
error (Errors.msg "HTLPargen: RPcall not supported.")
- | RBtailcall sig ri lr =>
+ | FUtailcall sig ri lr =>
error (Errors.msg "HTLPargen: RPtailcall not supported.")
- | RBbuiltin e lb b n =>
+ | FUbuiltin e lb b n =>
error (Errors.msg "HTLPargen: RPbuildin not supported.")
end.
-Definition translate_cfi (fin rtrn stack preg: reg) (ni: node * cf_instr)
+Definition translate_cfi (fin rtrn preg: reg) (ni: node * cf_instr)
: mon unit :=
let (n, cfi) := ni in
- do (s, c) <- translate_cfi' fin rtrn stack preg cfi;
+ do (s, c) <- translate_cfi' fin rtrn preg cfi;
do _ <- add_control_instr n c;
add_data_instr n s.
-Definition transf_bblock (fin rtrn stack preg: reg) (ni : node * bblock)
+Definition transf_bblock (fin rtrn preg: reg) (ni : node * bblock)
: mon unit :=
let (n, bb) := ni in
do nstate <- create_new_state ((poslength bb.(bb_body)))%positive;
- do _ <- collectlist (translate_inst_list fin rtrn stack preg)
+ do _ <- collectlist (translate_inst_list fin rtrn preg)
(prange n (nstate + poslength bb.(bb_body) - 1)%positive
bb.(bb_body));
match bb.(bb_body) with
- | nil => translate_cfi fin rtrn stack preg (n, bb.(bb_exit))
- | _ => translate_cfi fin rtrn stack preg (nstate, bb.(bb_exit))
+ | nil => translate_cfi fin rtrn preg (n, bb.(bb_exit))
+ | _ => translate_cfi fin rtrn preg (nstate, bb.(bb_exit))
end.
-Definition decide_order a b c d e f g : {module_ordering a b c d e f g} + {True}.
+(*Definition decide_order a b c d e f g : {module_ordering a b c d e f g} + {True}.
refine (match bool_dec ((a <? b) && (b <? c) && (c <? d)
&& (d <? e) && (e <? f) && (f <? g))%positive true with
| left t => left _
@@ -797,56 +799,65 @@ Definition decide_order a b c d e f g : {module_ordering a b c d e f g} + {True}
simplify; repeat match goal with
| H: context[(_ <? _)%positive] |- _ => apply Pos.ltb_lt in H
end; unfold module_ordering; auto.
-Defined.
+Defined.*)
-Definition transf_module (f: function) : mon HTL.module.
- refine (
+Lemma clk_greater :
+ forall ram clk r',
+ Some ram = Some r' -> (clk < ram_addr r')%positive.
+Proof. Admitted.
+
+Definition declare_ram (r: ram) : mon unit :=
+ do _ <- declare_reg None r.(ram_en) 1;
+ do _ <- declare_reg None r.(ram_u_en) 1;
+ do _ <- declare_reg None r.(ram_wr_en) 1;
+ do _ <- declare_reg None r.(ram_addr) 32;
+ do _ <- declare_reg None r.(ram_d_in) 32;
+ do _ <- declare_reg None r.(ram_d_out) 32;
+ do _ <- declare_arr None r.(ram_mem) 32 r.(ram_size);
+ ret tt.
+
+Definition transf_module (f: function) : mon HTL.module :=
if stack_correct f.(fn_stacksize) then
do fin <- create_reg (Some Voutput) 1;
do rtrn <- create_reg (Some Voutput) 32;
- do (stack, stack_len) <- create_arr None 32
- (Z.to_nat (f.(fn_stacksize) / 4));
do preg <- create_reg None 32;
- do _ <- collectlist (transf_bblock fin rtrn stack preg)
+ do _ <- collectlist (transf_bblock fin rtrn preg)
(Maps.PTree.elements f.(fn_code));
do _ <- collectlist (fun r => declare_reg (Some Vinput) r 32)
f.(fn_params);
do start <- create_reg (Some Vinput) 1;
do rst <- create_reg (Some Vinput) 1;
do clk <- create_reg (Some Vinput) 1;
- do current_state <- get;
- match zle (Z.pos (max_pc_map current_state.(st_datapath)))
- Integers.Int.max_unsigned,
+ match get_ram 0 (fn_funct_units f) with
+ | Some (_, r) =>
+ do _ <- declare_ram r;
+ do current_state <- get;
+ match zle (Z.pos (max_pc_map current_state.(st_datapath)))
+ Integers.Int.max_unsigned,
zle (Z.pos (max_pc_map current_state.(st_controllogic)))
Integers.Int.max_unsigned,
- decide_order (st_st current_state) fin rtrn stack start rst clk,
max_list_dec (fn_params f) (st_st current_state)
- with
- | left LEDATA, left LECTRL, left MORD, left WFPARAMS =>
- ret (HTL.mkmodule
- f.(fn_params)
- current_state.(st_datapath)
- current_state.(st_controllogic)
- f.(fn_entrypoint)
- current_state.(st_st)
- stack
- stack_len
- fin
- rtrn
- start
- rst
- clk
- current_state.(st_scldecls)
- current_state.(st_arrdecls)
- None
- (conj (max_pc_wf _ LECTRL) (max_pc_wf _ LEDATA))
- MORD
- _
- WFPARAMS)
- | _, _, _, _ => error (Errors.msg "More than 2^32 states.")
+ with
+ | left LEDATA, left LECTRL, left WFPARAMS =>
+ ret (HTL.mkmodule
+ f.(fn_params)
+ current_state.(st_datapath)
+ current_state.(st_controllogic)
+ f.(fn_entrypoint)
+ current_state.(st_st)
+ fin
+ rtrn
+ start
+ rst
+ clk
+ current_state.(st_scldecls)
+ current_state.(st_arrdecls)
+ r)
+ | _, _, _=> error (Errors.msg "More than 2^32 states.")
+ end
+ | _ => error (Errors.msg "Stack RAM not found.")
end
- else error (Errors.msg "Stack size misalignment.")); discriminate.
-Defined.
+ else error (Errors.msg "Stack size misalignment.").
Definition max_state (f: function) : state :=
let st := Pos.succ (max_reg_function f) in
@@ -863,7 +874,7 @@ Definition transl_module (f : function) : Errors.res HTL.module :=
Definition transl_fundef := transf_partial_fundef transl_module.
-Definition main_is_internal (p : RTLPar.program) : bool :=
+Definition main_is_internal (p : RTLParFU.program) : bool :=
let ge := Globalenvs.Genv.globalenv p in
match Globalenvs.Genv.find_symbol ge p.(AST.prog_main) with
| Some b =>
@@ -874,7 +885,7 @@ Definition main_is_internal (p : RTLPar.program) : bool :=
| _ => false
end.
-Definition transl_program (p : RTLBlockInstr.program) : Errors.res HTL.program :=
+Definition transl_program (p : RTLParFU.program) : Errors.res HTL.program :=
if main_is_internal p
then transform_partial_program transl_fundef p
else Errors.Error (Errors.msg "Main function is not Internal.").
diff --git a/src/hls/HTLgen.v b/src/hls/HTLgen.v
index 3f4e513..c793b1b 100644
--- a/src/hls/HTLgen.v
+++ b/src/hls/HTLgen.v
@@ -32,6 +32,7 @@ Require Import vericert.hls.AssocMap.
Require Import vericert.hls.HTL.
Require Import vericert.hls.ValueInt.
Require Import vericert.hls.Verilog.
+Require Import vericert.hls.FunctionalUnits.
#[local] Hint Resolve AssocMap.gempty : htlh.
#[local] Hint Resolve AssocMap.gso : htlh.
@@ -583,7 +584,7 @@ Proof.
simplify. transitivity (Z.pos (max_pc_map m)); eauto.
Qed.
-Definition decide_order a b c d e f g : {module_ordering a b c d e f g} + {True}.
+(*Definition decide_order a b c d e f g : {module_ordering a b c d e f g} + {True}.
refine (match bool_dec ((a <? b) && (b <? c) && (c <? d)
&& (d <? e) && (e <? f) && (f <? g))%positive true with
| left t => left _
@@ -592,7 +593,7 @@ Definition decide_order a b c d e f g : {module_ordering a b c d e f g} + {True}
simplify; repeat match goal with
| H: context[(_ <? _)%positive] |- _ => apply Pos.ltb_lt in H
end; unfold module_ordering; auto.
-Defined.
+Defined.*)
Definition transf_module (f: function) : mon HTL.module.
refine (
@@ -605,21 +606,24 @@ Definition transf_module (f: function) : mon HTL.module.
do start <- create_reg (Some Vinput) 1;
do rst <- create_reg (Some Vinput) 1;
do clk <- create_reg (Some Vinput) 1;
+ do r_en <- create_reg None 1;
+ do r_u_en <- create_reg None 1;
+ do r_addr <- create_reg None 32;
+ do r_wr_en <- create_reg None 1;
+ do r_d_in <- create_reg None 32;
+ do r_d_out <- create_reg None 32;
do current_state <- get;
match zle (Z.pos (max_pc_map current_state.(st_datapath))) Integers.Int.max_unsigned,
zle (Z.pos (max_pc_map current_state.(st_controllogic))) Integers.Int.max_unsigned,
- decide_order (st_st current_state) fin rtrn stack start rst clk,
max_list_dec (RTL.fn_params f) (st_st current_state)
with
- | left LEDATA, left LECTRL, left MORD, left WFPARAMS =>
+ | left LEDATA, left LECTRL, left WFPARAMS =>
ret (HTL.mkmodule
f.(RTL.fn_params)
current_state.(st_datapath)
current_state.(st_controllogic)
f.(fn_entrypoint)
current_state.(st_st)
- stack
- stack_len
fin
rtrn
start
@@ -627,12 +631,8 @@ Definition transf_module (f: function) : mon HTL.module.
clk
current_state.(st_scldecls)
current_state.(st_arrdecls)
- None
- (conj (max_pc_wf _ LECTRL) (max_pc_wf _ LEDATA))
- MORD
- _
- WFPARAMS)
- | _, _, _, _ => error (Errors.msg "More than 2^32 states.")
+ (mk_ram stack_len stack r_en r_u_en r_addr r_wr_en r_d_in r_d_out))
+ | _, _, _ => error (Errors.msg "More than 2^32 states.")
end
else error (Errors.msg "Stack size misalignment.")); discriminate.
Defined.
diff --git a/src/hls/HTLgenproof.v b/src/hls/HTLgenproof.v
index fc7af6b..bf1ef1c 100644
--- a/src/hls/HTLgenproof.v
+++ b/src/hls/HTLgenproof.v
@@ -34,6 +34,7 @@ Require vericert.hls.HTL.
Require Import vericert.hls.HTLgen.
Require Import vericert.hls.HTLgenspec.
Require Import vericert.hls.ValueInt.
+Require Import vericert.hls.FunctionalUnits.
Require vericert.hls.Verilog.
Require Import Lia.
@@ -62,10 +63,10 @@ Definition state_st_wf (m : HTL.module) (s : HTL.state) :=
Inductive match_arrs (m : HTL.module) (f : RTL.function) (sp : Values.val) (mem : mem) :
Verilog.assocmap_arr -> Prop :=
| match_arr : forall asa stack,
- asa ! (m.(HTL.mod_stk)) = Some stack /\
+ asa ! (m.(HTL.mod_ram).(ram_mem)) = Some stack /\
stack.(arr_length) = Z.to_nat (f.(RTL.fn_stacksize) / 4) /\
(forall ptr,
- 0 <= ptr < Z.of_nat m.(HTL.mod_stk_len) ->
+ 0 <= ptr < Z.of_nat m.(HTL.mod_ram).(ram_size) ->
opt_val_value_lessdef (Mem.loadv AST.Mint32 mem
(Values.Val.offset_ptr sp (Integers.Ptrofs.repr (4 * ptr))))
(Option.default (NToValue 0)
@@ -1003,26 +1004,29 @@ Section CORRECTNESS.
constructor.
Qed.
- (** The proof of semantic preservation for the translation of instructions
- is a simulation argument based on diagrams of the following form:
-<<
- match_states
- code st rs ---------------- State m st assoc
- || |
- || |
- || |
- \/ v
- code st rs' --------------- State m st assoc'
- match_states
->>
- where [tr_code c data control fin rtrn st] is assumed to hold.
-
- The precondition and postcondition is that that should hold is [match_assocmaps rs assoc].
- *)
+(*|
+The proof of semantic preservation for the translation of instructions is a
+simulation argument based on diagrams of the following form:
+
+::
+> match_states
+> code st rs ------------------------- State m st assoc
+> || |
+> || |
+> || |
+> \/ v
+> code st rs' ------------------------ State m st assoc'
+> match_states
+
+where ``tr_code c data control fin rtrn st`` is assumed to hold.
+
+The precondition and postcondition is that that should hold is ``match_assocmaps
+rs assoc``.
+|*)
Definition transl_instr_prop (instr : RTL.instruction) : Prop :=
forall m asr asa fin rtrn st stmt trans res,
- tr_instr fin rtrn st (m.(HTL.mod_stk)) instr stmt trans ->
+ tr_instr fin rtrn st (m.(HTL.mod_ram).(ram_mem)) instr stmt trans ->
exists asr' asa',
HTL.step tge (HTL.State res m st asr asa) Events.E0 (HTL.State res m st asr' asa').
@@ -1090,7 +1094,7 @@ Section CORRECTNESS.
apply Smallstep.plus_one.
eapply HTL.step_module; eauto.
inv CONST; assumption.
- inv CONST; assumption.
+ inv CONST; assumption.
(* processing of state *)
econstructor.
crush.
@@ -1098,9 +1102,9 @@ Section CORRECTNESS.
econstructor.
econstructor.
- all: invert MARR; big_tac.
+ all: invert MARR; big_tac. Abort.
- inv CONST; constructor; simplify; rewrite AssocMap.gso; auto; lia.
+(* inv CONST; constructor; simplify; rewrite AssocMap.gso; auto; lia.
Unshelve. exact tt.
Qed.
@@ -2568,7 +2572,7 @@ Section CORRECTNESS.
Smallstep.plus HTL.step tge R1 Events.E0 R2 /\ match_states (RTL.State s f sp pc' rs m) R2.
Proof.
intros s f sp pc rs m arg tbl n pc' H H0 H1 R1 MSTATE.
-
+
#[local] Hint Resolve transl_ijumptable_correct : htlproof.*)
Lemma transl_ireturn_correct:
@@ -2862,13 +2866,13 @@ Section CORRECTNESS.
Proof.
induction 1; eauto with htlproof; (intros; inv_state).
Qed.
- #[local] Hint Resolve transl_step_correct : htlproof.
+ #[local] Hint Resolve transl_step_correct : htlproof.*)
Theorem transf_program_correct:
Smallstep.forward_simulation (RTL.semantics prog) (HTL.semantics tprog).
Proof.
eapply Smallstep.forward_simulation_plus; eauto with htlproof.
apply senv_preserved.
- Qed.
+ (*Qed.*)Admitted.
End CORRECTNESS.
diff --git a/src/hls/HTLgenspec.v b/src/hls/HTLgenspec.v
index 8746ba2..165fa91 100644
--- a/src/hls/HTLgenspec.v
+++ b/src/hls/HTLgenspec.v
@@ -31,6 +31,7 @@ Require Import vericert.hls.ValueInt.
Require Import vericert.hls.HTL.
Require Import vericert.hls.HTLgen.
Require Import vericert.hls.AssocMap.
+Require Import vericert.hls.FunctionalUnits.
#[local] Hint Resolve Maps.PTree.elements_keys_norepet : htlspec.
#[local] Hint Resolve Maps.PTree.elements_correct : htlspec.
@@ -119,11 +120,15 @@ Ltac monadInv H :=
((progress simpl in H) || unfold F in H); monadInv1 H
end.
-(** * Relational specification of the translation *)
+(*|
+===========================================
+Relational specification of the translation
+===========================================
-(** We now define inductive predicates that characterise the fact that the
+We now define inductive predicates that characterise the fact that the
statemachine that is created by the translation contains the correct
-translations for each of the elements *)
+translations for each of the elements.
+|*)
Inductive tr_instr (fin rtrn st stk : reg) : RTL.instruction -> stmnt -> stmnt -> Prop :=
| tr_instr_Inop :
@@ -159,7 +164,7 @@ Inductive tr_instr (fin rtrn st stk : reg) : RTL.instruction -> stmnt -> stmnt -
translate_arr_access mem addr args stk s = OK c s' i ->
tr_instr fin rtrn st stk (RTL.Istore mem addr args src n) (Vnonblock c (Vvar src))
(state_goto st n).
-(*| tr_instr_Ijumptable :
+(* tr_instr_Ijumptable :
forall cexpr tbl r,
cexpr = tbl_to_case_expr st tbl ->
tr_instr fin rtrn st stk (RTL.Ijumptable r tbl) (Vskip) (Vcase (Vvar r) cexpr (Some Vskip)).*)
@@ -178,12 +183,13 @@ Inductive tr_code (c : RTL.code) (pc : RTL.node) (i : RTL.instruction) (stmnts t
Inductive tr_module (f : RTL.function) : module -> Prop :=
tr_module_intro :
- forall data control fin rtrn st stk stk_len m start rst clk scldecls arrdecls wf1 wf2 wf3 wf4,
+ forall data control fin rtrn st stk stk_len m start rst clk scldecls arrdecls r_en r_u_en r_addr r_wr_en r_d_in r_d_out,
m = (mkmodule f.(RTL.fn_params)
data
control
f.(RTL.fn_entrypoint)
- st stk stk_len fin rtrn start rst clk scldecls arrdecls None wf1 wf2 wf3 wf4) ->
+ st fin rtrn start rst clk scldecls arrdecls
+ (mk_ram stk_len stk r_en r_u_en r_addr r_wr_en r_d_in r_d_out)) ->
(forall pc i, Maps.PTree.get pc f.(RTL.fn_code) = Some i ->
tr_code f.(RTL.fn_code) pc i data control fin rtrn st stk) ->
stk_len = Z.to_nat (f.(RTL.fn_stacksize) / 4) ->
@@ -196,6 +202,12 @@ Inductive tr_module (f : RTL.function) : module -> Prop :=
start = ((RTL.max_reg_function f) + 5)%positive ->
rst = ((RTL.max_reg_function f) + 6)%positive ->
clk = ((RTL.max_reg_function f) + 7)%positive ->
+ r_en = ((RTL.max_reg_function f) + 8)%positive ->
+ r_u_en = ((RTL.max_reg_function f) + 9)%positive ->
+ r_addr = ((RTL.max_reg_function f) + 10)%positive ->
+ r_wr_en = ((RTL.max_reg_function f) + 11)%positive ->
+ r_d_in = ((RTL.max_reg_function f) + 12)%positive ->
+ r_d_out = ((RTL.max_reg_function f) + 13)%positive ->
tr_module f m.
#[local] Hint Constructors tr_module : htlspec.
@@ -644,7 +656,7 @@ Proof.
assert (EQ3D := EQ3).
apply collect_declare_datapath_trans in EQ3.
apply collect_declare_controllogic_trans in EQ3D.
- replace (st_controllogic s10) with (st_controllogic s3) by congruence.
+ (*replace (st_controllogic s10) with (st_controllogic s3) by congruence.
replace (st_datapath s10) with (st_datapath s3) by congruence.
replace (st_st s10) with (st_st s3) by congruence.
eapply iter_expand_instr_spec; eauto with htlspec.
@@ -654,3 +666,4 @@ Proof.
erewrite <- collect_declare_freshreg_trans; try eassumption.
lia.
Qed.
+*)Admitted.
diff --git a/src/hls/IfConversion.v b/src/hls/IfConversion.v
index b397d43..2516109 100644
--- a/src/hls/IfConversion.v
+++ b/src/hls/IfConversion.v
@@ -26,14 +26,17 @@ Require Import vericert.common.Vericertlib.
Require Import vericert.hls.RTLBlockInstr.
Require Import vericert.hls.RTLBlock.
Require Import vericert.hls.Predicate.
+Require Import vericert.bourdoncle.Bourdoncle.
+
+Parameter build_bourdoncle : function -> (bourdoncle * PMap.t N).
(*|
=============
-If conversion
+If-Conversion
=============
-This conversion is a verified conversion from RTLBlock back to itself, which performs if-conversion
-on basic blocks to make basic blocks larger.
+This conversion is a verified conversion from RTLBlock back to itself, which
+performs if-conversion on basic blocks to make basic blocks larger.
|*)
Definition combine_pred (p: pred_op) (optp: option pred_op) :=
@@ -96,11 +99,34 @@ Definition find_all_backedges (c: code) : list node :=
Definition has_backedge (entry: node) (be: list node) :=
any (fun x => Pos.eqb entry x) be.
-Definition find_blocks_with_cond (c: code) : list (node * bblock) :=
+Fixpoint get_loops (b: bourdoncle): list node :=
+ match b with
+ | L h b' => h::(fold_right (fun a b => get_loops a ++ b) nil b')
+ | I h => nil
+ end.
+
+Definition is_loop (b: list node) (n: node) :=
+ any (fun x => Pos.eqb x n) b.
+
+Definition is_flat_cfi (n: cf_instr) :=
+ match n with
+ | RBcond _ _ _ _ => false
+ | RBjumptable _ _ => false
+ | RBpred_cf _ _ _ => false
+ | _ => true
+ end.
+
+Definition is_flat (c: code) (succ: node) :=
+ match c ! succ with
+ | Some bblock => is_flat_cfi bblock.(bb_exit)
+ | None => false
+ end.
+
+Definition find_blocks_with_cond ep (b: list node) (c: code) : list (node * bblock) :=
let backedges := find_all_backedges c in
List.filter (fun x => is_cond_cfi (snd x).(bb_exit) &&
- negb (has_backedge (fst x) backedges) &&
- all (fun x' => negb (has_backedge x' backedges))
+ (negb (is_loop b (fst x)) || Pos.eqb (fst x) ep) &&
+ all (fun x' => is_flat c x')
(successors_instr (snd x).(bb_exit))
) (PTree.elements c).
@@ -109,8 +135,10 @@ Definition if_convert_code (p: nat * code) (nb: node * bblock) :=
(S (fst p), PTree.set (fst nb) nbb (snd p)).
Definition transf_function (f: function) : function :=
+ let (b, _) := build_bourdoncle f in
+ let b' := get_loops b in
let (_, c) := List.fold_left if_convert_code
- (find_blocks_with_cond f.(fn_code))
+ (find_blocks_with_cond f.(fn_entrypoint) b' f.(fn_code))
(1%nat, f.(fn_code)) in
mkfunction f.(fn_sig) f.(fn_params) f.(fn_stacksize) c f.(fn_entrypoint).
diff --git a/src/hls/Memorygen.v b/src/hls/Memorygen.v
index 96c11c3..e28bbc7 100644
--- a/src/hls/Memorygen.v
+++ b/src/hls/Memorygen.v
@@ -35,6 +35,7 @@ Require Import vericert.hls.Verilog.
Require Import vericert.hls.HTL.
Require Import vericert.hls.AssocMap.
Require Import vericert.hls.Array.
+Require Import vericert.hls.FunctionalUnits.
Local Open Scope positive.
Local Open Scope assocmap.
@@ -43,7 +44,7 @@ Local Open Scope assocmap.
#[local] Hint Resolve max_reg_stmnt_lt_stmnt_tree : mgen.
#[local] Hint Resolve max_stmnt_lt_module : mgen.
-Lemma int_eq_not_false : forall x, Int.eq x (Int.not x) = false.
+(*Lemma int_eq_not_false : forall x, Int.eq x (Int.not x) = false.
Proof.
intros. unfold Int.eq.
rewrite Int.unsigned_not.
@@ -459,8 +460,8 @@ Lemma forall_ram_lt :
forall_ram (fun x => x < max_reg_module m + 1) r.
Proof.
assert (X: forall a b c, a < b + 1 -> a < Pos.max c b + 1) by lia.
- unfold forall_ram; simplify; unfold max_reg_module; repeat apply X;
- unfold max_reg_ram; rewrite H; try lia.
+ unfold forall_ram; simplify; unfold HTL.max_reg_module; repeat apply X;
+ unfold HTL.max_reg_ram; rewrite H; try lia.
Qed.
#[local] Hint Resolve forall_ram_lt : mgen.
@@ -3201,3 +3202,4 @@ Section CORRECTNESS.
Qed.
End CORRECTNESS.
+*)
diff --git a/src/hls/Partition.ml b/src/hls/Partition.ml
index 19c6048..545277b 100644
--- a/src/hls/Partition.ml
+++ b/src/hls/Partition.ml
@@ -1,6 +1,6 @@
- (*
+(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*)
+(* [[file:../../docs/basic-block-generation.org::partition-main][partition-main]] *)
open Printf
open Clflags
open Camlcoq
@@ -28,7 +29,7 @@ open Op
open RTLBlockInstr
open RTLBlock
-(* Assuming that the nodes of the CFG [code] are numbered in reverse postorder (cf. pass
+(** Assuming that the nodes of the CFG [code] are numbered in reverse postorder (cf. pass
[Renumber]), an edge from [n] to [s] is a normal edge if [s < n] and a back-edge otherwise. *)
let find_edge i n =
let succ = RTL.successors_instr i in
@@ -65,14 +66,14 @@ let rec next_bblock_from_RTL is_start e (c : RTL.code) s i =
match trans_inst, succ with
| (None, Some i'), _ ->
if List.exists (fun x -> x = s) (snd e) && not is_start then
- Errors.OK { bb_body = []; bb_exit = RBgoto s }
+ Errors.OK { bb_body = [RBnop]; bb_exit = RBgoto s }
else
- Errors.OK { bb_body = []; bb_exit = i' }
+ Errors.OK { bb_body = [RBnop]; bb_exit = i' }
| (Some i', None), (s', Some i_n)::[] ->
if List.exists (fun x -> x = s) (fst e) then
Errors.OK { bb_body = [i']; bb_exit = RBgoto s' }
else if List.exists (fun x -> x = s) (snd e) && not is_start then
- Errors.OK { bb_body = []; bb_exit = RBgoto s }
+ Errors.OK { bb_body = [RBnop]; bb_exit = RBgoto s }
else begin
match next_bblock_from_RTL false e c s' i_n with
| Errors.OK bb ->
@@ -122,3 +123,4 @@ let function_from_RTL f =
}
let partition = function_from_RTL
+(* partition-main ends here *)
diff --git a/src/hls/Pipeline.v b/src/hls/Pipeline.v
index 7f1485a..67ab1f5 100644
--- a/src/hls/Pipeline.v
+++ b/src/hls/Pipeline.v
@@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*)
-Require Import compcert.lib.Maps.
+(*Require Import compcert.lib.Maps.
Require Import compcert.common.AST.
Require Import compcert.backend.RTL.
@@ -26,3 +26,4 @@ Definition transf_fundef := transf_fundef pipeline.
Definition transf_program : program -> program :=
transform_program transf_fundef.
+*)
diff --git a/src/hls/PipelineOp.v b/src/hls/PipelineOp.v
new file mode 100644
index 0000000..bb01ff9
--- /dev/null
+++ b/src/hls/PipelineOp.v
@@ -0,0 +1,193 @@
+(*
+ * Vericert: Verified high-level synthesis.
+ * Copyright (C) 2021 Yann Herklotz <yann@yannherklotz.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *)
+
+Require Import Coq.Lists.List.
+
+Require Import compcert.backend.Registers.
+Require Import compcert.common.AST.
+Require Import compcert.common.Errors.
+Require Import compcert.common.Globalenvs.
+Require Import compcert.lib.Integers.
+Require Import compcert.lib.Maps.
+Require Import compcert.verilog.Op.
+
+
+Require Import vericert.common.Vericertlib.
+Require Import vericert.hls.RTLBlockInstr.
+Require Import vericert.hls.RTLPar.
+Require Import vericert.hls.FunctionalUnits.
+
+Import Option.Notation.
+
+Local Open Scope positive.
+
+Definition div_pos (il: nat * list nat) x :=
+ let (i, l) := il in
+ match x with
+ | RBop _ Odiv _ _ => (S i, i :: l)
+ | RBop _ Odivu _ _ => (S i, i :: l)
+ | RBop _ Omod _ _ => (S i, i :: l)
+ | RBop _ Omodu _ _ => (S i, i :: l)
+ | _ => (S i, l)
+ end.
+
+Definition div_pos_in_list (il: nat * list (nat * nat)) bb :=
+ let (i, l) := il in
+ let dp := snd (List.fold_left div_pos bb (0%nat, nil)) in
+ (S i, (List.map (fun x => (i, x)) dp) ++ l).
+
+Definition div_pos_in_block (il: nat * list (nat * nat * nat)) bb :=
+ let (i, l) := il in
+ let dp := snd (List.fold_left div_pos_in_list bb (0%nat, nil)) in
+ (S i, (List.map (fun (yx : nat * nat) => let (y, x) := yx in (i, y, x)) dp) ++ l).
+
+Definition find_divs (bb: bblock) :=
+ snd (List.fold_left div_pos_in_block bb.(bb_body) (0%nat, nil)).
+
+Fixpoint mapi' {A B: Type} (n: nat) (f: nat -> A -> B) (l: list A): list B :=
+ match l with
+ | nil => nil
+ | a :: b => f n a :: mapi' (S n) f b
+ end.
+
+Definition mapi {A B: Type} := @mapi' A B 0.
+
+Definition map_at {A: Type} (n: nat) (f: A -> A) (l: list A): list A :=
+ mapi (fun i il =>
+ if Nat.eqb n i
+ then f il
+ else il
+ ) l.
+
+Definition map_at_err {A: Type} (n: nat) (f: A -> A) (l: list A): option (list A) :=
+ if (Datatypes.length l <=? n)%nat
+ then None
+ else Some (map_at n f l).
+
+(*Definition replace_div' sdiv udiv (d: instr) :=
+ match d with
+ | RBop op Odiv args dst => RBpiped op sdiv args
+ | RBop op Odivu args dst => RBpiped op udiv args
+ | RBop op Omod args dst => RBpiped op sdiv args
+ | RBop op Omodu args dst => RBpiped op udiv args
+ | _ => d
+ end.
+
+Definition get_sdiv (fu: funct_unit) : option (reg * reg * reg) :=
+ match fu with
+ | SignedDiv s a b d _ => Some (a, b, d)
+ | _ => None
+ end.
+
+Definition get_udiv (fu: funct_unit) : option (reg * reg * reg) :=
+ match fu with
+ | UnsignedDiv s a b d _ => Some (a, b, d)
+ | _ => None
+ end.
+
+Definition get_smod (fu: funct_unit) : option (reg * reg * reg) :=
+ match fu with
+ | SignedDiv s a b _ d => Some (a, b, d)
+ | _ => None
+ end.
+
+Definition get_umod (fu: funct_unit) : option (reg * reg * reg) :=
+ match fu with
+ | UnsignedDiv s a b _ d => Some (a, b, d)
+ | _ => None
+ end.
+
+Definition bind3 {A B C D: Type}
+ (f: option (A * B * C))
+ (g: A -> B -> C -> option D) : option D :=
+ match f with
+ | Some (a, b, c) => g a b c
+ | None => None
+ end.
+
+Notation "'do' ( X , Y , Z ) <- A ; B" := (bind3 A (fun X Y Z => B))
+ (at level 200, X ident, Y ident, Z ident, A at level 100, B at level 200).
+
+Definition replace_div_error (fu: funct_units) (bb: bb) (loc: nat * nat * nat) :=
+ match loc with
+ | (z, y, x) =>
+ do sdiv <- fu.(avail_sdiv);
+ do udiv <- fu.(avail_udiv);
+ do sfu <- PTree.get sdiv fu.(avail_units);
+ do ufu <- PTree.get udiv fu.(avail_units);
+ do z' <- List.nth_error bb z;
+ do y' <- List.nth_error z' y;
+ do x' <- List.nth_error y' x;
+ let transf := map_at z (map_at y (map_at x (replace_div' sdiv udiv))) bb in
+ match x' with
+ | RBop op Odiv args dst =>
+ do (s1, s2, src) <- get_sdiv sfu;
+ map_at_err (z + 32)%nat (fun x => (RBassign op sdiv src dst :: nil) :: x) transf
+ | RBop op Odivu args dst =>
+ do (s1, s2, src) <- get_udiv ufu;
+ map_at_err (z + 32)%nat (fun x => (RBassign op sdiv src dst :: nil) :: x) transf
+ | RBop op Omod args dst =>
+ do (s1, s2, src) <- get_smod sfu;
+ map_at_err (z + 32)%nat (fun x => (RBassign op sdiv src dst :: nil) :: x) transf
+ | RBop op Omodu args dst =>
+ do (s1, s2, src) <- get_umod ufu;
+ map_at_err (z + 32)%nat (fun x => (RBassign op sdiv src dst :: nil) :: x) transf
+ | _ => None
+ end
+ end.
+
+Definition replace_div (fu: funct_units) (bb: bb) loc :=
+ match replace_div_error fu bb loc with
+ | Some bb' => bb'
+ | _ => bb
+ end.
+
+Definition transf_code (i: code * funct_units) (bbn: node * bblock) :=
+ let (c, fu) := i in
+ let (n, bb) := bbn in
+ let divs := find_divs bb in
+ match divs with
+ | nil => (PTree.set n bb c, fu)
+ | _ =>
+ (PTree.set n (mk_bblock (List.fold_left (replace_div fu) divs bb.(bb_body)) bb.(bb_exit)) c, fu)
+ end.
+
+Definition create_fu (r: reg) :=
+ let fu := PTree.set 2 (UnsignedDiv 32 (r+5) (r+6) (r+7) (r+8))
+ (PTree.set 1 (SignedDiv 32 (r+1) (r+2) (r+3) (r+4)) (PTree.empty _)) in
+ mk_avail_funct_units (Some 1) (Some 2) fu.
+
+Definition transf_function (f: function) : function :=
+ let fu := create_fu (max_reg_function f) in
+ let (c, fu') := List.fold_left transf_code
+ (PTree.elements f.(fn_code))
+ (PTree.empty bblock, fu) in
+ mkfunction
+ f.(fn_sig)
+ f.(fn_params)
+ f.(fn_stacksize)
+ c
+ fu'
+ f.(fn_entrypoint).
+
+Definition transf_fundef (fd: fundef) : fundef :=
+ transf_fundef transf_function fd.
+
+Definition transf_program (p: program) : program :=
+ transform_program transf_fundef p.
+*)
diff --git a/src/hls/Predicate.v b/src/hls/Predicate.v
index a2b5400..b19ae98 100644
--- a/src/hls/Predicate.v
+++ b/src/hls/Predicate.v
@@ -24,6 +24,8 @@ Notation "A ∨ B" := (Por A B) (at level 25) : pred_op.
Notation "⟂" := (Pfalse) : pred_op.
Notation "'T'" := (Ptrue) : pred_op.
+#[local] Open Scope pred_op.
+
Fixpoint sat_predicate (p: pred_op) (a: asgn) : bool :=
match p with
| Plit (b, p') => if b then a (Pos.to_nat p') else negb (a (Pos.to_nat p'))
@@ -33,6 +35,234 @@ Fixpoint sat_predicate (p: pred_op) (a: asgn) : bool :=
| Por p1 p2 => sat_predicate p1 a || sat_predicate p2 a
end.
+Definition sat_equiv p1 p2 := forall c, sat_predicate p1 c = sat_predicate p2 c.
+
+Lemma equiv_symm : forall a b, sat_equiv a b -> sat_equiv b a.
+Proof. crush. Qed.
+
+Lemma equiv_trans : forall a b c, sat_equiv a b -> sat_equiv b c -> sat_equiv a c.
+Proof. crush. Qed.
+
+Lemma equiv_refl : forall a, sat_equiv a a.
+Proof. crush. Qed.
+
+#[global]
+Instance Equivalence_SAT : Equivalence sat_equiv :=
+ { Equivalence_Reflexive := equiv_refl ;
+ Equivalence_Symmetric := equiv_symm ;
+ Equivalence_Transitive := equiv_trans ;
+ }.
+
+#[global]
+Instance SATSetoid : Setoid pred_op :=
+ { equiv := sat_equiv; }.
+
+#[global]
+Instance PandProper : Proper (equiv ==> equiv ==> equiv) Pand.
+Proof.
+ unfold Proper. simplify. unfold "==>".
+ intros.
+ unfold sat_equiv in *. intros.
+ simplify. rewrite H0. rewrite H.
+ auto.
+Qed.
+
+#[global]
+Instance PorProper : Proper (equiv ==> equiv ==> equiv) Por.
+Proof.
+ unfold Proper, "==>". simplify.
+ intros.
+ unfold sat_equiv in *. intros.
+ simplify. rewrite H0. rewrite H.
+ auto.
+Qed.
+
+#[global]
+Instance sat_predicate_Proper : Proper (equiv ==> eq ==> eq) sat_predicate.
+Proof.
+ unfold Proper, "==>". simplify.
+ intros.
+ unfold sat_equiv in *. subst.
+ apply H.
+Qed.
+
+Fixpoint negate (p: pred_op) :=
+ match p with
+ | Plit (b, pr) => Plit (negb b, pr)
+ | T => ⟂
+ | ⟂ => T
+ | A ∧ B => negate A ∨ negate B
+ | A ∨ B => negate A ∧ negate B
+ end.
+
+Notation "¬ A" := (negate A) (at level 15) : pred_op.
+
+Lemma negate_correct :
+ forall h a, sat_predicate (negate h) a = negb (sat_predicate h a).
+Proof.
+ induction h; crush.
+ - repeat destruct_match; subst; crush; symmetry; apply negb_involutive.
+ - rewrite negb_andb; crush.
+ - rewrite negb_orb; crush.
+Qed.
+
+Definition unsat p := forall a, sat_predicate p a = false.
+Definition sat p := exists a, sat_predicate p a = true.
+
+Lemma unsat_correct1 :
+ forall a b c,
+ unsat (Pand a b) ->
+ sat_predicate a c = true ->
+ sat_predicate b c = false.
+Proof.
+ unfold unsat in *. intros.
+ simplify. specialize (H c).
+ apply andb_false_iff in H. inv H. rewrite H0 in H1. discriminate.
+ auto.
+Qed.
+
+Lemma unsat_correct2 :
+ forall a b c,
+ unsat (Pand a b) ->
+ sat_predicate b c = true ->
+ sat_predicate a c = false.
+Proof.
+ unfold unsat in *. intros.
+ simplify. specialize (H c).
+ apply andb_false_iff in H. inv H. auto. rewrite H0 in H1. discriminate.
+Qed.
+
+Lemma unsat_not a: unsat (a ∧ (¬ a)).
+Proof.
+ unfold unsat; simplify.
+ rewrite negate_correct.
+ auto with bool.
+Qed.
+
+Lemma unsat_commut a b: unsat (a ∧ b) -> unsat (b ∧ a).
+Proof. unfold unsat; simplify; eauto with bool. Qed.
+
+Lemma sat_imp_equiv :
+ forall a b,
+ unsat (a ∧ ¬ b ∨ ¬ a ∧ b) -> a == b.
+Proof.
+ simplify; unfold unsat, sat_equiv.
+ intros. specialize (H c); simplify.
+ rewrite negate_correct in *.
+ destruct (sat_predicate b c) eqn:X;
+ destruct (sat_predicate a c) eqn:X2;
+ crush.
+Qed.
+
+Lemma sat_predicate_and :
+ forall a b c,
+ sat_predicate (a ∧ b) c = sat_predicate a c && sat_predicate b c.
+Proof. crush. Qed.
+
+Lemma sat_predicate_or :
+ forall a b c,
+ sat_predicate (a ∨ b) c = sat_predicate a c || sat_predicate b c.
+Proof. crush. Qed.
+
+Lemma sat_equiv2 :
+ forall a b,
+ a == b -> unsat (a ∧ ¬ b ∨ ¬ a ∧ b).
+Proof.
+ unfold unsat, equiv; simplify.
+ repeat rewrite negate_correct.
+ repeat rewrite H.
+ rewrite andb_negb_r.
+ rewrite andb_negb_l. auto.
+Qed.
+
+Lemma sat_equiv3 :
+ forall a b,
+ unsat (a ∧ ¬ b ∨ b ∧ ¬ a) -> a == b.
+Proof.
+ simplify. unfold unsat, sat_equiv in *; intros.
+ specialize (H c); simplify.
+ rewrite negate_correct in *.
+ destruct (sat_predicate b c) eqn:X;
+ destruct (sat_predicate a c) eqn:X2;
+ crush.
+Qed.
+
+Lemma sat_equiv4 :
+ forall a b,
+ a == b -> unsat (a ∧ ¬ b ∨ b ∧ ¬ a).
+Proof.
+ unfold unsat, equiv; simplify.
+ repeat rewrite negate_correct.
+ repeat rewrite H.
+ rewrite andb_negb_r. auto.
+Qed.
+
+Definition simplify' (p: pred_op) :=
+ match p with
+ | (Plit (b1, a)) ∧ (Plit (b2, b)) as p' =>
+ if Pos.eqb a b then
+ if negb (xorb b1 b2) then Plit (b1, a) else ⟂
+ else p'
+ | (Plit (b1, a)) ∨ (Plit (b2, b)) as p' =>
+ if Pos.eqb a b then
+ if negb (xorb b1 b2) then Plit (b1, a) else T
+ else p'
+ | A ∧ T => A
+ | T ∧ A => A
+ | _ ∧ ⟂ => ⟂
+ | ⟂ ∧ _ => ⟂
+ | _ ∨ T => T
+ | T ∨ _ => T
+ | A ∨ ⟂ => A
+ | ⟂ ∨ A => A
+ | A => A
+ end.
+
+Lemma pred_op_dec :
+ forall p1 p2: pred_op,
+ { p1 = p2 } + { p1 <> p2 }.
+Proof. pose proof Pos.eq_dec. repeat decide equality. Qed.
+
+Fixpoint simplify (p: pred_op) :=
+ match p with
+ | A ∧ B =>
+ let A' := simplify A in
+ let B' := simplify B in
+ simplify' (A' ∧ B')
+ | A ∨ B =>
+ let A' := simplify A in
+ let B' := simplify B in
+ simplify' (A' ∨ B')
+ | T => T
+ | ⟂ => ⟂
+ | Plit a => Plit a
+ end.
+
+Lemma simplify'_correct :
+ forall h a,
+ sat_predicate (simplify' h) a = sat_predicate h a.
+Proof.
+ (*destruct h; crush; repeat destruct_match; crush;
+ solve [rewrite andb_true_r; auto | rewrite orb_false_r; auto].
+Qed.*) Admitted.
+
+Lemma simplify_correct :
+ forall h a,
+ sat_predicate (simplify h) a = sat_predicate h a.
+Proof.
+ Local Opaque simplify'.
+ induction h; crush.
+ - replace (sat_predicate h1 a && sat_predicate h2 a)
+ with (sat_predicate (simplify h1) a && sat_predicate (simplify h2) a)
+ by crush.
+ rewrite simplify'_correct. crush.
+ - replace (sat_predicate h1 a || sat_predicate h2 a)
+ with (sat_predicate (simplify h1) a || sat_predicate (simplify h2) a)
+ by crush.
+ rewrite simplify'_correct. crush.
+ Local Transparent simplify'.
+Qed.
+
Fixpoint mult {A: Type} (a b: list (list A)) : list (list A) :=
match a with
| nil => nil
@@ -162,11 +392,143 @@ Fixpoint trans_pred (p: pred_op) :
apply i0 in H0. auto.
Defined.
-Definition sat_pred (p: pred_op) :
+Definition bar (p1: lit): lit := (negb (fst p1), (snd p1)).
+
+Definition stseytin_or (cur p1 p2: lit) : formula :=
+ (bar cur :: p1 :: p2 :: nil)
+ :: (cur :: bar p1 :: nil)
+ :: (cur :: bar p2 :: nil) :: nil.
+
+Definition stseytin_and (cur p1 p2: lit) : formula :=
+ (cur :: bar p1 :: bar p2 :: nil)
+ :: (bar cur :: p1 :: nil)
+ :: (bar cur :: p2 :: nil) :: nil.
+
+Fixpoint xtseytin (next: nat) (p: pred_op) {struct p} : (nat * lit * formula) :=
+ match p with
+ | Plit (b, p') => (next, (b, Pos.to_nat p'), nil)
+ | Ptrue =>
+ ((next+1)%nat, (true, next), ((true, next)::nil)::nil)
+ | Pfalse =>
+ ((next+1)%nat, (true, next), ((false, next)::nil)::nil)
+ | Por p1 p2 =>
+ let '(m1, n1, f1) := xtseytin next p1 in
+ let '(m2, n2, f2) := xtseytin m1 p2 in
+ ((m2+1)%nat, (true, m2), stseytin_or (true, m2) n1 n2 ++ f1 ++ f2)
+ | Pand p1 p2 =>
+ let '(m1, n1, f1) := xtseytin next p1 in
+ let '(m2, n2, f2) := xtseytin m1 p2 in
+ ((m2+1)%nat, (true, m2), stseytin_and (true, m2) n1 n2 ++ f1 ++ f2)
+ end.
+
+Lemma stseytin_and_correct :
+ forall cur p1 p2 fm c,
+ stseytin_and cur p1 p2 = fm ->
+ satLit cur c ->
+ satLit p1 c /\ satLit p2 c ->
+ satFormula fm c.
+Proof.
+ intros.
+ unfold stseytin_and in *. rewrite <- H.
+ unfold satLit in *. destruct p1. destruct p2. destruct cur.
+ simpl in *|-. cbn. unfold satLit. cbn. crush.
+Qed.
+
+Lemma stseytin_and_correct2 :
+ forall cur p1 p2 fm c,
+ stseytin_and cur p1 p2 = fm ->
+ satFormula fm c ->
+ satLit cur c <-> satLit p1 c /\ satLit p2 c.
+Proof.
+ intros. split. intros. inv H1. unfold stseytin_and in *.
+ inv H0; try contradiction. Admitted.
+
+Lemma stseytin_or_correct :
+ forall cur p1 p2 fm c,
+ stseytin_or cur p1 p2 = fm ->
+ satLit cur c ->
+ satLit p1 c \/ satLit p2 c ->
+ satFormula fm c.
+Proof.
+ intros.
+ unfold stseytin_or in *. rewrite <- H. inv H1.
+ unfold satLit in *. destruct p1. destruct p2. destruct cur.
+ simpl in *|-. cbn. unfold satLit. cbn. crush.
+ unfold satLit in *. destruct p1. destruct p2. destruct cur.
+ simpl in *|-. cbn. unfold satLit. cbn. crush.
+Qed.
+
+Lemma stseytin_or_correct2 :
+ forall cur p1 p2 fm c,
+ stseytin_or cur p1 p2 = fm ->
+ satFormula fm c ->
+ satLit cur c <-> satLit p1 c \/ satLit p2 c.
+Proof. Admitted.
+
+Lemma xtseytin_correct :
+ forall p next l n fm c,
+ xtseytin next p = (n, l, fm) ->
+ sat_predicate p c = true <-> satFormula ((l::nil)::fm) c.
+Proof.
+ induction p.
+ - intros. simplify. destruct p.
+ inv H. split.
+ intros. destruct b. split; crush.
+ apply negb_true_iff in H.
+ split; crush.
+ intros. inv H. inv H0; try contradiction.
+ inv H. simplify. rewrite <- H0.
+ destruct b.
+ rewrite -> H0; auto.
+ rewrite -> H0; auto.
+ - admit.
+ - admit.
+ - intros. split. intros. simpl in H0.
+ apply andb_prop in H0. inv H0.
+ cbn in H.
+ repeat destruct_match; try discriminate; []. inv H. eapply IHp1 in Heqp.
+ eapply IHp2 in Heqp1. apply Heqp1 in H2.
+ apply Heqp in H1. inv H1. inv H2.
+ assert
+ (satFormula
+ (((true, n1) :: bar l0 :: bar l1 :: nil)
+ :: (bar (true, n1) :: l0 :: nil)
+ :: (bar (true, n1) :: l1 :: nil) :: nil) c).
+ eapply stseytin_and_correct. unfold stseytin_and. eauto.
+ unfold satLit. simpl. admit.
+ inv H; try contradiction. inv H1; try contradiction. eauto.
+Admitted.
+
+Fixpoint max_predicate (p: pred_op) : positive :=
+ match p with
+ | Plit (b, p) => p
+ | Ptrue => 1
+ | Pfalse => 1
+ | Pand a b => Pos.max (max_predicate a) (max_predicate b)
+ | Por a b => Pos.max (max_predicate a) (max_predicate b)
+ end.
+
+Definition tseytin (p: pred_op) :
+ {fm: formula | forall a,
+ sat_predicate p a = true <-> satFormula fm a}.
+ refine (
+ (match xtseytin (Pos.to_nat (max_predicate p + 1)) p as X
+ return xtseytin (Pos.to_nat (max_predicate p + 1)) p = X ->
+ {fm: formula | forall a, sat_predicate p a = true <-> satFormula fm a}
+ with (m, n, fm) => fun H => exist _ ((n::nil) :: fm) _
+ end) (eq_refl (xtseytin (Pos.to_nat (max_predicate p + 1)) p))).
+ intros. eapply xtseytin_correct; eauto. Defined.
+
+Definition tseytin_simple (p: pred_op) : formula :=
+ let m := Pos.to_nat (max_predicate p + 1) in
+ let '(m, n, fm) := xtseytin m p in
+ (n::nil) :: fm.
+
+Definition sat_pred_tseytin (p: pred_op) :
({al : alist | sat_predicate p (interp_alist al) = true}
+ {forall a : asgn, sat_predicate p a = false}).
refine
- ( match trans_pred p with
+ ( match tseytin p with
| exist _ fm _ =>
match satSolve fm with
| inleft (exist _ a _) => inleft (exist _ a _)
@@ -179,69 +541,33 @@ Definition sat_pred (p: pred_op) :
apply n. apply i. auto. auto.
Defined.
-Definition sat_pred_simple (p: pred_op) :=
- match sat_pred p with
- | inleft (exist _ al _) => Some al
+Definition sat_pred_simple (p: pred_op) : option alist :=
+ match sat_pred_tseytin p with
+ | inleft (exist _ a _) => Some a
| inright _ => None
end.
-#[local] Open Scope pred_op.
-
-Fixpoint negate (p: pred_op) :=
- match p with
- | Plit (b, pr) => Plit (negb b, pr)
- | T => ⟂
- | ⟂ => T
- | A ∧ B => negate A ∨ negate B
- | A ∨ B => negate A ∧ negate B
- end.
-
-Notation "¬ A" := (negate A) (at level 15) : pred_op.
-
-Lemma negate_correct :
- forall h a, sat_predicate (negate h) a = negb (sat_predicate h a).
-Proof.
- induction h; crush.
- - repeat destruct_match; subst; crush; symmetry; apply negb_involutive.
- - rewrite negb_andb; crush.
- - rewrite negb_orb; crush.
-Qed.
-
-Definition unsat p := forall a, sat_predicate p a = false.
-Definition sat p := exists a, sat_predicate p a = true.
-
-Lemma unsat_correct1 :
- forall a b c,
- unsat (Pand a b) ->
- sat_predicate a c = true ->
- sat_predicate b c = false.
-Proof.
- unfold unsat in *. intros.
- simplify. specialize (H c).
- apply andb_false_iff in H. inv H. rewrite H0 in H1. discriminate.
- auto.
-Qed.
-
-Lemma unsat_correct2 :
- forall a b c,
- unsat (Pand a b) ->
- sat_predicate b c = true ->
- sat_predicate a c = false.
-Proof.
- unfold unsat in *. intros.
- simplify. specialize (H c).
- apply andb_false_iff in H. inv H. auto. rewrite H0 in H1. discriminate.
-Qed.
+Definition sat_pred (p: pred_op) :
+ ({al : alist | sat_predicate p (interp_alist al) = true}
+ + {forall a : asgn, sat_predicate p a = false}).
+ refine
+ ( match trans_pred p with
+ | exist _ fm _ =>
+ match satSolve fm with
+ | inleft (exist _ a _) => inleft (exist _ a _)
+ | inright _ => inright _
+ end
+ end ).
+ - apply i in s0. auto.
+ - intros. specialize (n a). specialize (i a).
+ destruct (sat_predicate p a). exfalso.
+ apply n. apply i. auto. auto.
+Defined.
-Lemma unsat_not a: unsat (a ∧ (¬ a)).
-Proof.
- unfold unsat; simplify.
- rewrite negate_correct.
- auto with bool.
-Qed.
+#[local] Open Scope positive.
-Lemma unsat_commut a b: unsat (a ∧ b) -> unsat (b ∧ a).
-Proof. unfold unsat; simplify; eauto with bool. Qed.
+Compute tseytin_simple (Por (negate (Pand (Por (Plit (true, 1)) (Plit (true, 2))) (Plit (true, 3)))) (Plit (false, 4))).
+Compute sat_pred_simple (Por Pfalse (Pand (Plit (true, 1)) (Plit (false, 1)))).
Lemma sat_dec a: {sat a} + {unsat a}.
Proof.
@@ -252,118 +578,14 @@ Proof.
intros. tauto.
Qed.
-Definition sat_equiv p1 p2 := forall c, sat_predicate p1 c = sat_predicate p2 c.
-
-Lemma equiv_symm : forall a b, sat_equiv a b -> sat_equiv b a.
-Proof. crush. Qed.
-
-Lemma equiv_trans : forall a b c, sat_equiv a b -> sat_equiv b c -> sat_equiv a c.
-Proof. crush. Qed.
-
-Lemma equiv_refl : forall a, sat_equiv a a.
-Proof. crush. Qed.
-
-#[global]
-Instance Equivalence_SAT : Equivalence sat_equiv :=
- { Equivalence_Reflexive := equiv_refl ;
- Equivalence_Symmetric := equiv_symm ;
- Equivalence_Transitive := equiv_trans ;
- }.
-
-#[global]
-Instance SATSetoid : Setoid pred_op :=
- { equiv := sat_equiv; }.
-
-#[global]
-Instance PandProper : Proper (equiv ==> equiv ==> equiv) Pand.
-Proof.
- unfold Proper. simplify. unfold "==>".
- intros.
- unfold sat_equiv in *. intros.
- simplify. rewrite H0. rewrite H.
- auto.
-Qed.
-
-#[global]
-Instance PorProper : Proper (equiv ==> equiv ==> equiv) Por.
-Proof.
- unfold Proper, "==>". simplify.
- intros.
- unfold sat_equiv in *. intros.
- simplify. rewrite H0. rewrite H.
- auto.
-Qed.
-
-#[global]
-Instance sat_predicate_Proper : Proper (equiv ==> eq ==> eq) sat_predicate.
-Proof.
- unfold Proper, "==>". simplify.
- intros.
- unfold sat_equiv in *. subst.
- apply H.
-Qed.
-
-Lemma sat_imp_equiv :
- forall a b,
- unsat (a ∧ ¬ b ∨ ¬ a ∧ b) -> a == b.
-Proof.
- simplify; unfold unsat, sat_equiv.
- intros. specialize (H c); simplify.
- rewrite negate_correct in *.
- destruct (sat_predicate b c) eqn:X;
- destruct (sat_predicate a c) eqn:X2;
- crush.
-Qed.
-
-Lemma sat_predicate_and :
- forall a b c,
- sat_predicate (a ∧ b) c = sat_predicate a c && sat_predicate b c.
-Proof. crush. Qed.
-
-Lemma sat_predicate_or :
- forall a b c,
- sat_predicate (a ∨ b) c = sat_predicate a c || sat_predicate b c.
-Proof. crush. Qed.
-
-Lemma sat_equiv2 :
- forall a b,
- a == b -> unsat (a ∧ ¬ b ∨ ¬ a ∧ b).
-Proof.
- unfold unsat, equiv; simplify.
- repeat rewrite negate_correct.
- repeat rewrite H.
- rewrite andb_negb_r.
- rewrite andb_negb_l. auto.
-Qed.
-
-Lemma sat_equiv3 :
- forall a b,
- unsat (a ∧ ¬ b ∨ b ∧ ¬ a) -> a == b.
-Proof.
- simplify. unfold unsat, sat_equiv in *; intros.
- specialize (H c); simplify.
- rewrite negate_correct in *.
- destruct (sat_predicate b c) eqn:X;
- destruct (sat_predicate a c) eqn:X2;
- crush.
-Qed.
-
-Lemma sat_equiv4 :
- forall a b,
- a == b -> unsat (a ∧ ¬ b ∨ b ∧ ¬ a).
-Proof.
- unfold unsat, equiv; simplify.
- repeat rewrite negate_correct.
- repeat rewrite H.
- rewrite andb_negb_r. auto.
-Qed.
-
Definition equiv_check p1 p2 :=
- match sat_pred_simple (p1 ∧ ¬ p2 ∨ p2 ∧ ¬ p1) with
+ match sat_pred_simple (simplify (p1 ∧ ¬ p2 ∨ p2 ∧ ¬ p1)) with
| None => true
| _ => false
end.
+Compute equiv_check Pfalse (Pand (Plit (true, 1%positive)) (Plit (false, 1%positive))).
+
Lemma equiv_check_correct :
forall p1 p2, equiv_check p1 p2 = true -> p1 == p2.
Proof.
@@ -371,16 +593,24 @@ Proof.
destruct_match; try discriminate; [].
destruct_match. destruct_match. discriminate.
eapply sat_equiv3; eauto.
+ unfold unsat; intros.
+ rewrite <- simplify_correct. eauto.
Qed.
+Opaque simplify.
+Opaque simplify'.
+
Lemma equiv_check_correct2 :
forall p1 p2, p1 == p2 -> equiv_check p1 p2 = true.
Proof.
unfold equiv_check, equiv, sat_pred_simple. intros.
- destruct_match; auto. destruct_match; try discriminate. destruct_match.
+ destruct_match; auto. destruct_match; try discriminate.
+ destruct_match.
simplify.
apply sat_equiv4 in H. unfold unsat in H. simplify.
- clear Heqs. rewrite H in e. discriminate.
+ clear Heqs. rewrite simplify_correct in e.
+ specialize (H (interp_alist a)). simplify.
+ rewrite H1 in e. rewrite H0 in e. discriminate.
Qed.
Lemma equiv_check_dec :
@@ -444,60 +674,10 @@ Proof.
auto.
Qed.
-Definition simplify' (p: pred_op) :=
- match p with
- | A ∧ T => A
- | T ∧ A => A
- | _ ∧ ⟂ => ⟂
- | ⟂ ∧ _ => ⟂
- | _ ∨ T => T
- | T ∨ _ => T
- | A ∨ ⟂ => A
- | ⟂ ∨ A => A
- | A => A
- end.
-
-Lemma pred_op_dec :
- forall p1 p2: pred_op,
- { p1 = p2 } + { p1 <> p2 }.
-Proof. pose proof Pos.eq_dec. repeat decide equality. Qed.
-
-Fixpoint simplify (p: pred_op) :=
- match p with
- | A ∧ B =>
- let A' := simplify A in
- let B' := simplify B in
- simplify' (A' ∧ B')
- | A ∨ B =>
- let A' := simplify A in
- let B' := simplify B in
- simplify' (A' ∨ B')
- | T => T
- | ⟂ => ⟂
- | Plit a => Plit a
- end.
-
-Lemma simplify'_correct :
- forall h a,
- sat_predicate (simplify' h) a = sat_predicate h a.
-Proof.
- destruct h; crush; repeat destruct_match; crush;
- solve [rewrite andb_true_r; auto | rewrite orb_false_r; auto].
-Qed.
-
-Lemma simplify_correct :
- forall h a,
- sat_predicate (simplify h) a = sat_predicate h a.
+#[global]
+Instance simplifyProper : Proper (equiv ==> equiv) simplify.
Proof.
- Local Opaque simplify'.
- induction h; crush.
- - replace (sat_predicate h1 a && sat_predicate h2 a)
- with (sat_predicate (simplify h1) a && sat_predicate (simplify h2) a)
- by crush.
- rewrite simplify'_correct. crush.
- - replace (sat_predicate h1 a || sat_predicate h2 a)
- with (sat_predicate (simplify h1) a || sat_predicate (simplify h2) a)
- by crush.
- rewrite simplify'_correct. crush.
- Local Transparent simplify'.
+ unfold Proper, "==>". simplify. unfold "→".
+ intros. unfold sat_equiv; intros.
+ rewrite ! simplify_correct; auto.
Qed.
diff --git a/src/hls/PrintAbstr.ml b/src/hls/PrintAbstr.ml
new file mode 100644
index 0000000..c63fa02
--- /dev/null
+++ b/src/hls/PrintAbstr.ml
@@ -0,0 +1,39 @@
+(**open Camlcoq
+open Datatypes
+open Maps
+open AST
+open Abstr
+open PrintAST
+open Printf
+
+let rec expr_to_list = function
+ | Enil -> []
+ | Econs (e, el) -> e :: expr_to_list el
+
+let res pp = function
+ | Reg r -> fprintf pp "r%d" (P.to_int r)
+ | Pred r -> fprintf pp "p%d" (P.to_int r)
+ | Mem -> fprintf pp "M"
+
+let rec print_expression pp = function
+ | Ebase r -> fprintf pp "%a'" res r
+ | Eop (op, el) -> fprintf pp "(%a)" (PrintOp.print_operation print_expression) (op, expr_to_list el)
+ | Eload (chunk, addr, el, e) ->
+ fprintf pp "(%s[%a][%a])"
+ (name_of_chunk chunk) print_expression e
+ (PrintOp.print_addressing print_expression) (addr, expr_to_list el)
+ | Estore (e, chunk, addr, el, m) ->
+ fprintf pp "(%s[%a][%a] = %a)"
+ (name_of_chunk chunk) print_expression m
+ (PrintOp.print_addressing print_expression) (addr, expr_to_list el)
+ print_expression e
+ | Esetpred (c, el) ->
+ fprintf pp "(%a)" (PrintOp.print_condition print_expression) (c, expr_to_list el)
+
+let rec print_predicated pp = function
+ | NE.Coq_singleton (p, e) ->
+ fprintf pp "%a %a" PrintRTLBlockInstr.print_pred_option p print_expression e
+ | NE.Coq_cons ((p, e), pr) ->
+ fprintf pp "%a %a\n%a" PrintRTLBlockInstr.print_pred_option p print_expression e
+ print_predicated pr
+*)
diff --git a/src/hls/PrintRTLBlockInstr.ml b/src/hls/PrintRTLBlockInstr.ml
index 8e24575..b8e1e2e 100644
--- a/src/hls/PrintRTLBlockInstr.ml
+++ b/src/hls/PrintRTLBlockInstr.ml
@@ -23,9 +23,9 @@ let ros pp = function
| Coq_inr s -> fprintf pp "\"%s\"" (extern_atom s)
let rec print_pred_op pp = function
- | Plit p -> if fst p then pred pp (snd p) else fprintf pp "~ %a" pred (snd p)
- | Pand (p1, p2) -> fprintf pp "(%a & %a)" print_pred_op p1 print_pred_op p2
- | Por (p1, p2) -> fprintf pp "(%a | %a)" print_pred_op p1 print_pred_op p2
+ | Plit p -> if fst p then pred pp (snd p) else fprintf pp "~%a" pred (snd p)
+ | Pand (p1, p2) -> fprintf pp "(%a ∧ %a)" print_pred_op p1 print_pred_op p2
+ | Por (p1, p2) -> fprintf pp "(%a ∨ %a)" print_pred_op p1 print_pred_op p2
| Ptrue -> fprintf pp "T"
| Pfalse -> fprintf pp "⟂"
diff --git a/src/hls/PrintRTLParFU.ml b/src/hls/PrintRTLParFU.ml
new file mode 100644
index 0000000..ec4d851
--- /dev/null
+++ b/src/hls/PrintRTLParFU.ml
@@ -0,0 +1,120 @@
+(* *********************************************************************)
+(* *)
+(* The Compcert verified compiler *)
+(* *)
+(* Xavier Leroy, INRIA Paris-Rocquencourt *)
+(* *)
+(* Copyright Institut National de Recherche en Informatique et en *)
+(* Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the INRIA Non-Commercial License Agreement. *)
+(* *)
+(* *********************************************************************)
+
+(** Pretty-printers for RTL code *)
+
+open Printf
+open Camlcoq
+open Datatypes
+open Maps
+open AST
+open PrintRTLBlockInstr
+open RTLParFU
+open PrintAST
+
+(* Printing of RTL code *)
+
+let reg pp r =
+ fprintf pp "x%d" (P.to_int r)
+
+let rec regs pp = function
+ | [] -> ()
+ | [r] -> reg pp r
+ | r1::rl -> fprintf pp "%a, %a" reg r1 regs rl
+
+let ros pp = function
+ | Coq_inl r -> reg pp r
+ | Coq_inr s -> fprintf pp "\"%s\"" (extern_atom s)
+
+let print_bblock_body pp i =
+ fprintf pp "\t\t";
+ match i with
+ | FUnop -> fprintf pp "nop\n"
+ | FUop(p, op, ls, dst) ->
+ fprintf pp "%a %a = %a\n"
+ print_pred_option p reg dst (PrintOp.print_operation reg) (op, ls)
+ | FUsetpred (p', c, args, p) ->
+ fprintf pp "%a %a = %a\n"
+ print_pred_option p'
+ pred p
+ (PrintOp.print_condition reg) (c, args)
+ | _ -> assert false
+
+let rec print_bblock_exit pp i =
+ fprintf pp "\t\t";
+ match i with
+ | FUcall(_, fn, args, res, _) ->
+ fprintf pp "%a = %a(%a)\n"
+ reg res ros fn regs args;
+ | FUtailcall(_, fn, args) ->
+ fprintf pp "tailcall %a(%a)\n"
+ ros fn regs args
+ | FUbuiltin(ef, args, res, _) ->
+ fprintf pp "%a = %s(%a)\n"
+ (print_builtin_res reg) res
+ (name_of_external ef)
+ (print_builtin_args reg) args
+ | FUcond(cond, args, s1, s2) ->
+ fprintf pp "if (%a) goto %d else goto %d\n"
+ (PrintOp.print_condition reg) (cond, args)
+ (P.to_int s1) (P.to_int s2)
+ | FUjumptable(arg, tbl) ->
+ let tbl = Array.of_list tbl in
+ fprintf pp "jumptable (%a)\n" reg arg;
+ for i = 0 to Array.length tbl - 1 do
+ fprintf pp "\tcase %d: goto %d\n" i (P.to_int tbl.(i))
+ done
+ | FUreturn None ->
+ fprintf pp "return\n"
+ | FUreturn (Some arg) ->
+ fprintf pp "return %a\n" reg arg
+ | FUgoto n ->
+ fprintf pp "goto %d\n" (P.to_int n)
+ | FUpred_cf (p, c1, c2) ->
+ fprintf pp "if %a then (%a) else (%a)\n" print_pred_op p print_bblock_exit c1 print_bblock_exit c2
+
+let print_bblock pp (pc, i) =
+ fprintf pp "%5d:{\n" pc;
+ List.iter (fun x -> fprintf pp "{\n";
+ List.iter (fun x -> fprintf pp "( "; List.iter (print_bblock_body pp) x; fprintf pp " )") x;
+ fprintf pp "}\n") i.bb_body;
+ print_bblock_exit pp i.bb_exit;
+ fprintf pp "\t}\n\n"
+
+let print_function pp id f =
+ fprintf pp "%s(%a) {\n" (extern_atom id) regs f.fn_params;
+ let instrs =
+ List.sort
+ (fun (pc1, _) (pc2, _) -> compare pc2 pc1)
+ (List.rev_map
+ (fun (pc, i) -> (P.to_int pc, i))
+ (PTree.elements f.fn_code)) in
+ List.iter (print_bblock pp) instrs;
+ fprintf pp "}\n\n"
+
+let print_globdef pp (id, gd) =
+ match gd with
+ | Gfun(Internal f) -> print_function pp id f
+ | _ -> ()
+
+let print_program pp (prog: program) =
+ List.iter (print_globdef pp) prog.prog_defs
+
+let destination : string option ref = ref None
+
+let print_if passno prog =
+ match !destination with
+ | None -> ()
+ | Some f ->
+ let oc = open_out (f ^ "." ^ Z.to_string passno) in
+ print_program oc prog;
+ close_out oc
diff --git a/src/hls/PrintVerilog.ml b/src/hls/PrintVerilog.ml
index fbb26c5..46b001e 100644
--- a/src/hls/PrintVerilog.ml
+++ b/src/hls/PrintVerilog.ml
@@ -28,6 +28,7 @@ open Clflags
open Printf
open VericertClflags
+open FunctionalUnits
module PMap = Map.Make (struct
type t = P.t
@@ -152,9 +153,9 @@ let declarearr (t, _) =
let print_io = function
| Some Vinput -> "input", false
- | Some Voutput -> "output reg", true
+ | Some Voutput -> "output logic", true
| Some Vinout -> "inout", false
- | None -> "reg", true
+ | None -> "logic", true
let decl i = function
| Vdecl (io, r, sz) -> concat [indent i; declare (print_io io) (r, sz)]
@@ -180,6 +181,20 @@ let rec intersperse c = function
let make_io i io r = concat [indent i; io; " "; register r; ";\n"]
+(**let print_funct_units clk = function
+ | SignedDiv (stages, numer, denom, quot, rem) ->
+ sprintf ("div_signed #(.stages(%d)) divs(.clk(%s), " ^^
+ ".clken(1'b1), .numer(%s), .denom(%s), " ^^
+ ".quotient(%s), .remain(%s))\n")
+ (P.to_int stages)
+ (register clk) (register numer) (register denom) (register quot) (register rem)
+ | UnsignedDiv (stages, numer, denom, quot, rem) ->
+ sprintf ("div_unsigned #(.stages(%d)) divs(.clk(%s), " ^^
+ ".clken(1'b1), .numer(%s), .denom(%s), " ^^
+ ".quotient(%s), .remain(%s))\n")
+ (P.to_int stages)
+ (register clk) (register numer) (register denom) (register quot) (register rem)*)
+
let compose f g x = g x |> f
let testbench = "module testbench;
diff --git a/src/hls/RICtransf.v b/src/hls/RICtransf.v
new file mode 100644
index 0000000..3b82b29
--- /dev/null
+++ b/src/hls/RICtransf.v
@@ -0,0 +1,87 @@
+(*
+ * Vericert: Verified high-level synthesis.
+ * Copyright (C) 2022 Yann Herklotz <yann@yannherklotz.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *)
+
+Require Import compcert.common.AST.
+Require Import compcert.common.Errors.
+Require Import compcert.common.Globalenvs.
+Require Import compcert.lib.Integers.
+Require Import compcert.lib.Maps.
+
+Require Import vericert.common.Vericertlib.
+Require Import vericert.hls.RTLBlockInstr.
+Require Import vericert.hls.RTLPar.
+Require Import vericert.hls.Predicate.
+
+(*|
+=====================
+Reverse If-Conversion
+=====================
+
+This transformation takes a scheduling RTLPar block and removes any predicates
+from it. It can then be trivially transformed into linear code again. It works
+by iteratively selecting a predicate, then creating a branch based on it and
+placing subsequent instructions in one branch or the other.
+|*)
+
+Fixpoint existsb_val {A B} (f: A -> option B) (l : list A) : option B :=
+ match l with
+ | nil => None
+ | a :: l0 =>
+ match f a, existsb_val f l0 with
+ | _, Some v => Some v
+ | Some v, _ => Some v
+ | _, _ => None
+ end
+ end.
+
+Definition includes_setpred (bb: list (list instr)) :=
+ existsb_val (existsb_val (fun x => match x with RBsetpred a _ _ _ => Some a | _ => None end)) bb.
+
+Definition add_bb (should_split: bool) (i: list (list instr))
+ (bbc: list (list (list instr)) * list (list (list instr))) :=
+ match bbc with
+ | (a, b) => if should_split then (a, i::b) else (i::a, b)
+ end.
+
+Fixpoint first_split (saw_pred: bool) (bb: list bb) :=
+ match bb with
+ | a :: b =>
+ match includes_setpred a with
+ | Some v =>
+ let (_, res) := first_split true b in
+ (Some v, add_bb saw_pred a res)
+ | _ =>
+ let (v, res) := first_split saw_pred b in
+ (v, add_bb saw_pred a res)
+ end
+ | nil => (None, (nil, nil))
+ end.
+
+Definition split_bb (fresh: node) (b: list bb) : list bb * list bb * list bb :=
+ match first_split false b with
+ | (Some p, (bb1, bb2)) => (bb1 ++ bb2, nil, nil)
+ | (None, (bb1, bb2)) => (bb1 ++ bb2, nil, nil)
+ end.
+
+Definition transf_function (f: function) : function := f.
+
+Definition transf_fundef (fd: fundef) : fundef :=
+ transf_fundef transf_function fd.
+
+Definition transf_program (p: program) : program :=
+ transform_program transf_fundef p.
diff --git a/src/hls/RTLBlock.v b/src/hls/RTLBlock.v
index bf5c37a..60b6948 100644
--- a/src/hls/RTLBlock.v
+++ b/src/hls/RTLBlock.v
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020-2021 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,13 @@ Require Import compcert.verilog.Op.
Require Import vericert.hls.RTLBlockInstr.
-Definition bb := list instr.
+(*|
+========
+RTLBlock
+========
+|*)
+
+Definition bb := instr.
Definition bblock := @bblock bb.
Definition code := @code bb.
@@ -40,64 +46,92 @@ Definition program := @program bb.
Definition funsig := @funsig bb.
Definition stackframe := @stackframe bb.
Definition state := @state bb.
+
Definition genv := @genv bb.
+(*|
+Semantics
+=========
+
+We first describe the semantics by assuming a global program environment with
+type ~genv~ which was declared earlier.
+|*)
+
Section RELSEM.
Context (ge: genv).
- Inductive step_instr_list: val -> instr_state -> list instr -> instr_state -> Prop :=
- | exec_RBcons:
- forall state i state' state'' instrs sp,
- step_instr ge sp state i state' ->
- step_instr_list sp state' instrs state'' ->
- step_instr_list sp state (i :: instrs) state''
- | exec_RBnil:
- forall state sp,
- step_instr_list sp state nil state.
-
- Inductive step: state -> trace -> state -> Prop :=
+(*|
+Instruction list step
+---------------------
+
+The ``step_instr_list`` definition describes the execution of a list of
+instructions in one big step, inductively traversing the list of instructions
+and applying the ``step_instr``.
+|*)
+
+ Inductive step_instr_list:
+ val -> instr_state -> list instr -> instr_state -> Prop :=
+ | exec_RBcons:
+ forall state i state' state'' instrs sp,
+ step_instr ge sp state i state' ->
+ step_instr_list sp state' instrs state'' ->
+ step_instr_list sp state (i :: instrs) state''
+ | exec_RBnil:
+ forall state sp,
+ step_instr_list sp state nil state.
+
+(*|
+Top-level step
+--------------
+
+The step function itself then uses this big step of the list of instructions to
+then show a transition from basic block to basic block.
+|*)
+
+ Variant step: state -> trace -> state -> Prop :=
| exec_bblock:
forall s f sp pc rs rs' m m' t s' bb pr pr',
f.(fn_code)!pc = Some bb ->
- step_instr_list sp (mk_instr_state rs pr m) bb.(bb_body) (mk_instr_state rs' pr' m') ->
- step_cf_instr ge (State s f sp pc rs' pr' m') bb.(bb_exit) t s' ->
- step (State s f sp pc rs pr m) t s'
+ step_instr_list sp (mk_instr_state rs pr m) bb.(bb_body)
+ (mk_instr_state rs' pr' m') ->
+ step_cf_instr ge (State s f sp pc nil rs' pr' m') bb.(bb_exit) t s' ->
+ step (State s f sp pc nil rs pr m) t s'
| exec_function_internal:
forall s f args m m' stk,
Mem.alloc m 0 f.(fn_stacksize) = (m', stk) ->
step (Callstate s (Internal f) args m)
- E0 (State s
- f
- (Vptr stk Ptrofs.zero)
- f.(fn_entrypoint)
- (init_regs args f.(fn_params))
- (PMap.init false)
- m')
+ E0 (State s f
+ (Vptr stk Ptrofs.zero)
+ f.(fn_entrypoint)
+ nil
+ (init_regs args f.(fn_params))
+ (PMap.init false)
+ m')
| exec_function_external:
forall s ef args res t m m',
external_call ef ge args m t res m' ->
step (Callstate s (External ef) args m)
- t (Returnstate s res m')
+ t (Returnstate s res m')
| exec_return:
forall res f sp pc rs s vres m pr,
step (Returnstate (Stackframe res f sp pc rs pr :: s) vres m)
- E0 (State s f sp pc (rs#res <- vres) pr m).
+ E0 (State s f sp pc nil (rs#res <- vres) pr m).
End RELSEM.
Inductive initial_state (p: program): state -> Prop :=
- | initial_state_intro: forall b f m0,
- let ge := Genv.globalenv p in
- Genv.init_mem p = Some m0 ->
- Genv.find_symbol ge p.(prog_main) = Some b ->
- Genv.find_funct_ptr ge b = Some f ->
- funsig f = signature_main ->
- initial_state p (Callstate nil f nil m0).
+| initial_state_intro: forall b f m0,
+ let ge := Genv.globalenv p in
+ Genv.init_mem p = Some m0 ->
+ Genv.find_symbol ge p.(prog_main) = Some b ->
+ Genv.find_funct_ptr ge b = Some f ->
+ funsig f = signature_main ->
+ initial_state p (Callstate nil f nil m0).
Inductive final_state: state -> int -> Prop :=
- | final_state_intro: forall r m,
- final_state (Returnstate nil (Vint r) m) r.
+| final_state_intro: forall r m,
+ final_state (Returnstate nil (Vint r) m) r.
Definition semantics (p: program) :=
Semantics step (initial_state p) final_state (Genv.globalenv p).
diff --git a/src/hls/RTLBlockInstr.v b/src/hls/RTLBlockInstr.v
index d9f3e74..4631b5a 100644
--- a/src/hls/RTLBlockInstr.v
+++ b/src/hls/RTLBlockInstr.v
@@ -1,20 +1,32 @@
-(*
- * Vericert: Verified high-level synthesis.
- * Copyright (C) 2021 Yann Herklotz <yann@yannherklotz.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *)
+(*|
+..
+ Vericert: Verified high-level synthesis.
+ Copyright (C) 2019-2022 Yann Herklotz <yann@yannherklotz.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+=============
+RTLBlockInstr
+=============
+
+These instructions are used for ``RTLBlock`` and ``RTLPar``, so that they have
+consistent instructions, which greatly simplifies the proofs, as they will by
+default have the same instruction syntax and semantics. The only changes are
+therefore at the top-level of the instructions.
+
+.. coq:: none
+|*)
Require Import Coq.micromega.Lia.
@@ -31,38 +43,41 @@ Require Import compcert.verilog.Op.
Require Import Predicate.
Require Import Vericertlib.
-(*|
-=====================
-RTLBlock Instructions
-=====================
+Definition node := positive.
-These instructions are used for ``RTLBlock`` and ``RTLPar``, so that they have consistent
-instructions, which greatly simplifies the proofs, as they will by default have the same instruction
-syntax and semantics. The only changes are therefore at the top-level of the instructions.
+(*|
+.. index::
+ triple: definition; RTLBlockInstr; instruction
Instruction Definition
======================
-First, we define the instructions that can be placed into a basic block, meaning they won't branch.
-The main changes to how instructions are defined in ``RTL``, is that these instructions don't have a
-next node, as they will be in a basic block, and they also have an optional predicate (``pred_op``).
+First, we define the instructions that can be placed into a basic block, meaning
+they won't branch. The main changes to how instructions are defined in ``RTL``,
+is that these instructions don't have a next node, as they will be in a basic
+block, and they also have an optional predicate (``pred_op``).
|*)
-Definition node := positive.
-
Inductive instr : Type :=
| RBnop : instr
-| RBop : option pred_op -> operation -> list reg -> reg -> instr
-| RBload : option pred_op -> memory_chunk -> addressing -> list reg -> reg -> instr
-| RBstore : option pred_op -> memory_chunk -> addressing -> list reg -> reg -> instr
-| RBsetpred : option pred_op -> condition -> list reg -> predicate -> instr.
+| RBop :
+ option pred_op -> operation -> list reg -> reg -> instr
+| RBload :
+ option pred_op -> memory_chunk -> addressing -> list reg -> reg -> instr
+| RBstore :
+ option pred_op -> memory_chunk -> addressing -> list reg -> reg -> instr
+| RBsetpred :
+ option pred_op -> condition -> list reg -> predicate -> instr.
(*|
+.. index::
+ triple: definition; RTLBlockInstr; control-flow instruction
+
Control-Flow Instruction Definition
===================================
-These are the instructions that count as control-flow, and will be placed at the end of the basic
-blocks.
+These are the instructions that count as control-flow, and will be placed at the
+end of the basic blocks.
|*)
Inductive cf_instr : Type :=
@@ -77,7 +92,7 @@ Inductive cf_instr : Type :=
| RBpred_cf : pred_op -> cf_instr -> cf_instr -> cf_instr.
(*|
-Helper functions
+Helper Functions
================
|*)
@@ -90,35 +105,36 @@ Fixpoint successors_instr (i : cf_instr) : list node :=
| RBjumptable arg tbl => tbl
| RBreturn optarg => nil
| RBgoto n => n :: nil
- | RBpred_cf p c1 c2 => concat (successors_instr c1 :: successors_instr c2 :: nil)
+ | RBpred_cf p c1 c2 =>
+ concat (successors_instr c1 :: successors_instr c2 :: nil)
end.
Definition max_reg_instr (m: positive) (i: instr) :=
match i with
| RBnop => m
| RBop p op args res =>
- fold_left Pos.max args (Pos.max res m)
+ fold_left Pos.max args (Pos.max res m)
| RBload p chunk addr args dst =>
- fold_left Pos.max args (Pos.max dst m)
+ fold_left Pos.max args (Pos.max dst m)
| RBstore p chunk addr args src =>
- fold_left Pos.max args (Pos.max src m)
+ fold_left Pos.max args (Pos.max src m)
| RBsetpred p' c args p =>
- fold_left Pos.max args m
+ fold_left Pos.max args m
end.
Fixpoint max_reg_cfi (m : positive) (i : cf_instr) :=
match i with
| RBcall sig (inl r) args res s =>
- fold_left Pos.max args (Pos.max r (Pos.max res m))
+ fold_left Pos.max args (Pos.max r (Pos.max res m))
| RBcall sig (inr id) args res s =>
- fold_left Pos.max args (Pos.max res m)
+ fold_left Pos.max args (Pos.max res m)
| RBtailcall sig (inl r) args =>
- fold_left Pos.max args (Pos.max r m)
+ fold_left Pos.max args (Pos.max r m)
| RBtailcall sig (inr id) args =>
- fold_left Pos.max args m
+ fold_left Pos.max args m
| RBbuiltin ef args res s =>
fold_left Pos.max (params_of_builtin_args args)
- (fold_left Pos.max (params_of_builtin_res res) m)
+ (fold_left Pos.max (params_of_builtin_res res) m)
| RBcond cond args ifso ifnot => fold_left Pos.max args m
| RBjumptable arg tbl => Pos.max arg m
| RBreturn None => m
@@ -134,7 +150,7 @@ Definition eval_predf (pr: predset) (p: pred_op) :=
sat_predicate p (fun x => pr !! (Pos.of_nat x)).
#[global]
-Instance eval_predf_Proper : Proper (eq ==> equiv ==> eq) eval_predf.
+ Instance eval_predf_Proper : Proper (eq ==> equiv ==> eq) eval_predf.
Proof.
unfold Proper. simplify. unfold "==>".
intros.
@@ -159,9 +175,10 @@ Lemma eval_predf_pr_equiv :
eval_predf ps p = eval_predf ps' p.
Proof.
induction p; simplify; auto;
- try (unfold eval_predf; simplify; repeat (destruct_match; []); inv Heqp0; rewrite <- H; auto);
- [repeat rewrite eval_predf_Pand|repeat rewrite eval_predf_Por];
- erewrite IHp1; try eassumption; erewrite IHp2; eauto.
+ try (unfold eval_predf; simplify;
+ repeat (destruct_match; []); inv Heqp0; rewrite <- H; auto);
+ [repeat rewrite eval_predf_Pand|repeat rewrite eval_predf_Por];
+ erewrite IHp1; try eassumption; erewrite IHp2; eauto.
Qed.
Fixpoint init_regs (vl: list val) (rl: list reg) {struct rl} : regset :=
@@ -177,16 +194,16 @@ Instruction State
Definition of the instruction state, which contains the following:
:is_rs: This is the current state of the registers.
-:is_ps: This is the current state of the predicate registers, which is in a separate namespace and
- area compared to the standard registers in ``is_rs``.
+:is_ps: This is the current state of the predicate registers, which is in a
+ separate namespace and area compared to the standard registers in [is_rs].
:is_mem: The current state of the memory.
|*)
Record instr_state := mk_instr_state {
- is_rs: regset;
- is_ps: predset;
- is_mem: mem;
-}.
+ is_rs: regset;
+ is_ps: predset;
+ is_mem: mem;
+ }.
(*|
Top-Level Type Definitions
@@ -198,19 +215,19 @@ Section DEFINITION.
Context {bblock_body: Type}.
Record bblock : Type := mk_bblock {
- bb_body: bblock_body;
- bb_exit: cf_instr
- }.
+ bb_body: list bblock_body;
+ bb_exit: cf_instr
+ }.
Definition code: Type := PTree.t bblock.
Record function: Type := mkfunction {
- fn_sig: signature;
- fn_params: list reg;
- fn_stacksize: Z;
- fn_code: code;
- fn_entrypoint: node
- }.
+ fn_sig: signature;
+ fn_params: list reg;
+ fn_stacksize: Z;
+ fn_code: code;
+ fn_entrypoint: node
+ }.
Definition fundef := AST.fundef function.
@@ -224,35 +241,45 @@ Section DEFINITION.
Inductive stackframe : Type :=
| Stackframe:
- forall (res: reg) (**r where to store the result *)
- (f: function) (**r calling function *)
- (sp: val) (**r stack pointer in calling function *)
- (pc: node) (**r program point in calling function *)
- (rs: regset) (**r register state in calling function *)
- (pr: predset), (**r predicate state of the calling function *)
+ forall (res: reg) (**r where to store the result *)
+ (f: function) (**r calling function *)
+ (sp: val) (**r stack pointer in calling function *)
+ (pc: node) (**r program point in calling function *)
+ (rs: regset) (**r register state in calling function *)
+ (pr: predset), (**r predicate state of the calling
+ function *)
stackframe.
- Inductive state : Type :=
- | State:
+(*|
+State Definition
+----------------
+
+Definition of the ``state`` type, which is used by the ``step`` functions.
+|*)
+
+ Variant state : Type :=
+ | State:
forall (stack: list stackframe) (**r call stack *)
(f: function) (**r current function *)
(sp: val) (**r stack pointer *)
(pc: node) (**r current program point in [c] *)
+ (il: list bblock_body) (**r basic block body that is
+ currently executing. *)
(rs: regset) (**r register state *)
(pr: predset) (**r predicate register state *)
(m: mem), (**r memory state *)
- state
- | Callstate:
+ state
+ | Callstate:
forall (stack: list stackframe) (**r call stack *)
(f: fundef) (**r function to call *)
(args: list val) (**r arguments to the call *)
(m: mem), (**r memory state *)
- state
- | Returnstate:
+ state
+ | Returnstate:
forall (stack: list stackframe) (**r call stack *)
(v: val) (**r return value for the call *)
(m: mem), (**r memory state *)
- state.
+ state.
End DEFINITION.
@@ -274,94 +301,122 @@ Section RELSEM.
match ros with
| inl r => Genv.find_funct ge rs#r
| inr symb =>
- match Genv.find_symbol ge symb with
- | None => None
- | Some b => Genv.find_funct_ptr ge b
- end
+ match Genv.find_symbol ge symb with
+ | None => None
+ | Some b => Genv.find_funct_ptr ge b
+ end
end.
- Inductive eval_pred: option pred_op -> instr_state -> instr_state -> instr_state -> Prop :=
+ Inductive eval_pred:
+ option pred_op -> instr_state -> instr_state -> instr_state -> Prop :=
| eval_pred_true:
- forall i i' p,
+ forall i i' p,
eval_predf (is_ps i) p = true ->
eval_pred (Some p) i i' i'
| eval_pred_false:
- forall i i' p,
+ forall i i' p,
eval_predf (is_ps i) p = false ->
eval_pred (Some p) i i' i
| eval_pred_none:
- forall i i', eval_pred None i i' i.
+ forall i i', eval_pred None i i' i.
+
+ (*|
+.. index::
+ triple: semantics; RTLBlockInstr; instruction
+
+Step Instruction
+=============================
+|*)
Inductive step_instr: val -> instr_state -> instr -> instr_state -> Prop :=
| exec_RBnop:
- forall sp ist,
- step_instr sp ist RBnop ist
+ forall sp ist,
+ step_instr sp ist RBnop ist
| exec_RBop:
- forall op v res args rs m sp p ist pr,
- eval_operation ge sp op rs##args m = Some v ->
- eval_pred p (mk_instr_state rs pr m) (mk_instr_state (rs#res <- v) pr m) ist ->
- step_instr sp (mk_instr_state rs pr m) (RBop p op args res) ist
+ forall op v res args rs m sp p ist pr,
+ eval_operation ge sp op rs##args m = Some v ->
+ eval_pred p (mk_instr_state rs pr m)
+ (mk_instr_state (rs#res <- v) pr m) ist ->
+ step_instr sp (mk_instr_state rs pr m) (RBop p op args res) ist
| exec_RBload:
- forall addr rs args a chunk m v dst sp p pr ist,
- eval_addressing ge sp addr rs##args = Some a ->
- Mem.loadv chunk m a = Some v ->
- eval_pred p (mk_instr_state rs pr m) (mk_instr_state (rs#dst <- v) pr m) ist ->
- step_instr sp (mk_instr_state rs pr m) (RBload p chunk addr args dst) ist
+ forall addr rs args a chunk m v dst sp p pr ist,
+ eval_addressing ge sp addr rs##args = Some a ->
+ Mem.loadv chunk m a = Some v ->
+ eval_pred p (mk_instr_state rs pr m)
+ (mk_instr_state (rs#dst <- v) pr m) ist ->
+ step_instr sp (mk_instr_state rs pr m)
+ (RBload p chunk addr args dst) ist
| exec_RBstore:
- forall addr rs args a chunk m src m' sp p pr ist,
- eval_addressing ge sp addr rs##args = Some a ->
- Mem.storev chunk m a rs#src = Some m' ->
- eval_pred p (mk_instr_state rs pr m) (mk_instr_state rs pr m') ist ->
- step_instr sp (mk_instr_state rs pr m) (RBstore p chunk addr args src) ist
+ forall addr rs args a chunk m src m' sp p pr ist,
+ eval_addressing ge sp addr rs##args = Some a ->
+ Mem.storev chunk m a rs#src = Some m' ->
+ eval_pred p (mk_instr_state rs pr m)
+ (mk_instr_state rs pr m') ist ->
+ step_instr sp (mk_instr_state rs pr m)
+ (RBstore p chunk addr args src) ist
| exec_RBsetpred:
- forall sp rs pr m p c b args p' ist,
+ forall sp rs pr m p c b args p' ist,
Op.eval_condition c rs##args m = Some b ->
- eval_pred p' (mk_instr_state rs pr m) (mk_instr_state rs (pr#p <- b) m) ist ->
- step_instr sp (mk_instr_state rs pr m) (RBsetpred p' c args p) ist.
+ eval_pred p' (mk_instr_state rs pr m)
+ (mk_instr_state rs (pr#p <- b) m) ist ->
+ step_instr sp (mk_instr_state rs pr m)
+ (RBsetpred p' c args p) ist.
+
+ (*|
+.. index::
+ triple: semantics; RTLBlockInstr; control-flow instruction
+
+Step Control-Flow Instruction
+=============================
+|*)
Inductive step_cf_instr: state -> cf_instr -> trace -> state -> Prop :=
| exec_RBcall:
forall s f sp rs m res fd ros sig args pc pc' pr,
find_function ros rs = Some fd ->
funsig fd = sig ->
- step_cf_instr (State s f sp pc rs pr m) (RBcall sig ros args res pc')
- E0 (Callstate (Stackframe res f sp pc' rs pr :: s) fd rs##args m)
+ step_cf_instr (State s f sp pc nil rs pr m) (RBcall sig ros args res pc')
+ E0 (Callstate (Stackframe res f sp pc' rs pr :: s) fd rs##args m)
| exec_RBtailcall:
- forall s f stk rs m sig ros args fd m' pc pr,
+ forall s f stk rs m sig ros args fd m' pc pr,
find_function ros rs = Some fd ->
funsig fd = sig ->
Mem.free m stk 0 f.(fn_stacksize) = Some m' ->
- step_cf_instr (State s f (Vptr stk Ptrofs.zero) pc rs pr m) (RBtailcall sig ros args)
- E0 (Callstate s fd rs##args m')
+ step_cf_instr (State s f (Vptr stk Ptrofs.zero) pc nil rs pr m)
+ (RBtailcall sig ros args)
+ E0 (Callstate s fd rs##args m')
| exec_RBbuiltin:
- forall s f sp rs m ef args res pc' vargs t vres m' pc pr,
+ forall s f sp rs m ef args res pc' vargs t vres m' pc pr,
eval_builtin_args ge (fun r => rs#r) sp m args vargs ->
external_call ef ge vargs m t vres m' ->
- step_cf_instr (State s f sp pc rs pr m) (RBbuiltin ef args res pc')
- t (State s f sp pc' (regmap_setres res vres rs) pr m')
+ step_cf_instr (State s f sp pc nil rs pr m) (RBbuiltin ef args res pc')
+ t (State s f sp pc' nil (regmap_setres res vres rs) pr m')
| exec_RBcond:
- forall s f sp rs m cond args ifso ifnot b pc pc' pr,
+ forall s f sp rs m cond args ifso ifnot b pc pc' pr,
eval_condition cond rs##args m = Some b ->
pc' = (if b then ifso else ifnot) ->
- step_cf_instr (State s f sp pc rs pr m) (RBcond cond args ifso ifnot)
- E0 (State s f sp pc' rs pr m)
+ step_cf_instr (State s f sp pc nil rs pr m) (RBcond cond args ifso ifnot)
+ E0 (State s f sp pc' nil rs pr m)
| exec_RBjumptable:
- forall s f sp rs m arg tbl n pc pc' pr,
+ forall s f sp rs m arg tbl n pc pc' pr,
rs#arg = Vint n ->
list_nth_z tbl (Int.unsigned n) = Some pc' ->
- step_cf_instr (State s f sp pc rs pr m) (RBjumptable arg tbl)
- E0 (State s f sp pc' rs pr m)
+ step_cf_instr (State s f sp pc nil rs pr m) (RBjumptable arg tbl)
+ E0 (State s f sp pc' nil rs pr m)
| exec_RBreturn:
- forall s f stk rs m or pc m' pr,
+ forall s f stk rs m or pc m' pr,
Mem.free m stk 0 f.(fn_stacksize) = Some m' ->
- step_cf_instr (State s f (Vptr stk Ptrofs.zero) pc rs pr m) (RBreturn or)
- E0 (Returnstate s (regmap_optget or Vundef rs) m')
+ step_cf_instr (State s f (Vptr stk Ptrofs.zero) pc nil rs pr m) (RBreturn or)
+ E0 (Returnstate s (regmap_optget or Vundef rs) m')
| exec_RBgoto:
- forall s f sp pc rs pr m pc',
- step_cf_instr (State s f sp pc rs pr m) (RBgoto pc') E0 (State s f sp pc' rs pr m)
+ forall s f sp pc rs pr m pc',
+ step_cf_instr (State s f sp pc nil rs pr m) (RBgoto pc') E0
+ (State s f sp pc' nil rs pr m)
| exec_RBpred_cf:
- forall s f sp pc rs pr m cf1 cf2 st' p t,
- step_cf_instr (State s f sp pc rs pr m) (if eval_predf pr p then cf1 else cf2) t st' ->
- step_cf_instr (State s f sp pc rs pr m) (RBpred_cf p cf1 cf2) t st'.
+ forall s f sp pc rs pr m cf1 cf2 st' p t,
+ step_cf_instr (State s f sp pc nil rs pr m)
+ (if eval_predf pr p then cf1 else cf2) t st' ->
+ step_cf_instr (State s f sp pc nil rs pr m)
+ (RBpred_cf p cf1 cf2) t st'.
End RELSEM.
diff --git a/src/hls/RTLBlockgen.v b/src/hls/RTLBlockgen.v
index 889e104..dc65cc2 100644
--- a/src/hls/RTLBlockgen.v
+++ b/src/hls/RTLBlockgen.v
@@ -1,30 +1,190 @@
-(*
- * Vericert: Verified high-level synthesis.
- * Copyright (C) 2020 Yann Herklotz <yann@yannherklotz.com>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *)
+(*|
+..
+ Vericert: Verified high-level synthesis.
+ Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+===========
+RTLBlockgen
+===========
+
+.. coq:: none
+|*)
Require compcert.backend.RTL.
Require Import compcert.common.AST.
Require Import compcert.lib.Maps.
+Require Import compcert.lib.Integers.
+Require Import compcert.lib.Floats.
+Require Import vericert.common.DecEq.
+Require Import vericert.common.Vericertlib.
+Require Import vericert.hls.RTLBlockInstr.
Require Import vericert.hls.RTLBlock.
+#[local] Open Scope positive.
+
+(*|
+``find_block max nodes index``: Does not need to be sorted, because we use
+filter and the max fold function to find the desired element.
+|*)
+
+Definition find_block (max: positive) (nodes: list positive) (index: positive) : positive :=
+ List.fold_right Pos.min max (List.filter (fun x => (index <=? x)) nodes).
+
+(*Compute find_block 100 (2::94::48::39::19::nil) 40.*)
+
+(*|
+.. index::
+ triple: abstract interpretation; check instruction; RTLBlockgen
+
+Check Instruction
+=================
+
+Check if an instruction is a standard instruction that should be in a basic
+block.
+|*)
+
+Definition check_instr (n: positive) (istr: RTL.instruction) (istr': instr) :=
+ match istr, istr' with
+ | RTL.Inop n', RBnop => (n' + 1 =? n)
+ | RTL.Iop op args dst n', RBop None op' args' dst' =>
+ ceq operation_eq op op' &&
+ ceq list_pos_eq args args' &&
+ ceq peq dst dst' && (n' + 1 =? n)
+ | RTL.Iload chunk addr args dst n', RBload None chunk' addr' args' dst' =>
+ ceq memory_chunk_eq chunk chunk' &&
+ ceq addressing_eq addr addr' &&
+ ceq list_pos_eq args args' &&
+ ceq peq dst dst' &&
+ (n' + 1 =? n)
+ | RTL.Istore chunk addr args src n', RBstore None chunk' addr' args' src' =>
+ ceq memory_chunk_eq chunk chunk' &&
+ ceq addressing_eq addr addr' &&
+ ceq list_pos_eq args args' &&
+ ceq peq src src' &&
+ (n' + 1 =? n)
+ | _, _ => false
+ end.
+
+Definition check_cf_instr_body (istr: RTL.instruction) (istr': instr): bool :=
+ match istr, istr' with
+ | RTL.Iop op args dst _, RBop None op' args' dst' =>
+ ceq operation_eq op op' &&
+ ceq list_pos_eq args args' &&
+ ceq peq dst dst'
+ | RTL.Iload chunk addr args dst _, RBload None chunk' addr' args' dst' =>
+ ceq memory_chunk_eq chunk chunk' &&
+ ceq addressing_eq addr addr' &&
+ ceq list_pos_eq args args' &&
+ ceq peq dst dst'
+ | RTL.Istore chunk addr args src _, RBstore None chunk' addr' args' src' =>
+ ceq memory_chunk_eq chunk chunk' &&
+ ceq addressing_eq addr addr' &&
+ ceq list_pos_eq args args' &&
+ ceq peq src src'
+ | RTL.Inop _, RBnop
+ | RTL.Icall _ _ _ _ _, RBnop
+ | RTL.Itailcall _ _ _, RBnop
+ | RTL.Ibuiltin _ _ _ _, RBnop
+ | RTL.Icond _ _ _ _, RBnop
+ | RTL.Ijumptable _ _, RBnop
+ | RTL.Ireturn _, RBnop => true
+ | _, _ => false
+ end.
+
+Definition check_cf_instr (istr: RTL.instruction) (istr': cf_instr) :=
+ match istr, istr' with
+ | RTL.Inop n, RBgoto n' => (n =? n')
+ | RTL.Iop _ _ _ n, RBgoto n' => (n =? n')
+ | RTL.Iload _ _ _ _ n, RBgoto n' => (n =? n')
+ | RTL.Istore _ _ _ _ n, RBgoto n' => (n =? n')
+ | RTL.Icall sig (inl r) args dst n, RBcall sig' (inl r') args' dst' n' =>
+ ceq signature_eq sig sig' &&
+ ceq peq r r' &&
+ ceq list_pos_eq args args' &&
+ ceq peq dst dst' &&
+ (n =? n')
+ | RTL.Icall sig (inr i) args dst n, RBcall sig' (inr i') args' dst' n' =>
+ ceq signature_eq sig sig' &&
+ ceq peq i i' &&
+ ceq list_pos_eq args args' &&
+ ceq peq dst dst' &&
+ (n =? n')
+ | RTL.Itailcall sig (inl r) args, RBtailcall sig' (inl r') args' =>
+ ceq signature_eq sig sig' &&
+ ceq peq r r' &&
+ ceq list_pos_eq args args'
+ | RTL.Itailcall sig (inr r) args, RBtailcall sig' (inr r') args' =>
+ ceq signature_eq sig sig' &&
+ ceq peq r r' &&
+ ceq list_pos_eq args args'
+ | RTL.Icond cond args n1 n2, RBcond cond' args' n1' n2' =>
+ ceq condition_eq cond cond' &&
+ ceq list_pos_eq args args' &&
+ ceq peq n1 n1' && ceq peq n2 n2'
+ | RTL.Ijumptable r ns, RBjumptable r' ns' =>
+ ceq peq r r' && ceq list_pos_eq ns ns'
+ | RTL.Ireturn (Some r), RBreturn (Some r') =>
+ ceq peq r r'
+ | RTL.Ireturn None, RBreturn None => true
+ | _, _ => false
+ end.
+
+Definition is_cf_instr (n: positive) (i: RTL.instruction) :=
+ match i with
+ | RTL.Inop n' => negb (n' + 1 =? n)
+ | RTL.Iop _ _ _ n' => negb (n' + 1 =? n)
+ | RTL.Iload _ _ _ _ n' => negb (n' + 1 =? n)
+ | RTL.Istore _ _ _ _ n' => negb (n' + 1 =? n)
+ | RTL.Icall _ _ _ _ _ => true
+ | RTL.Itailcall _ _ _ => true
+ | RTL.Ibuiltin _ _ _ _ => true
+ | RTL.Icond _ _ _ _ => true
+ | RTL.Ijumptable _ _ => true
+ | RTL.Ireturn _ => true
+ end.
+
+Definition check_present_blocks (c: code) (n: list positive) (max: positive) (i: positive) (istr: RTL.instruction) :=
+ let blockn := find_block max n i in
+ match c ! blockn with
+ | Some istrs =>
+ match List.nth_error istrs.(bb_body) (Pos.to_nat blockn - Pos.to_nat i)%nat with
+ | Some istr' =>
+ if is_cf_instr i istr
+ then check_cf_instr istr istrs.(bb_exit) && check_cf_instr_body istr istr'
+ else check_instr i istr istr'
+ | None => false
+ end
+ | None => false
+ end.
+
Parameter partition : RTL.function -> Errors.res function.
-Definition transl_fundef := transf_partial_fundef partition.
+Definition transl_function (f: RTL.function) :=
+ match partition f with
+ | Errors.OK f' =>
+ let blockids := map fst (PTree.elements f'.(fn_code)) in
+ if forall_ptree (check_present_blocks f'.(fn_code) blockids (fold_right Pos.max 1 blockids))
+ f.(RTL.fn_code) then
+ Errors.OK f'
+ else Errors.Error (Errors.msg "check_present_blocks failed")
+ | Errors.Error msg => Errors.Error msg
+ end.
+
+Definition transl_fundef := transf_partial_fundef transl_function.
Definition transl_program : RTL.program -> Errors.res program :=
transform_partial_program transl_fundef.
diff --git a/src/hls/RTLBlockgenproof.v b/src/hls/RTLBlockgenproof.v
new file mode 100644
index 0000000..f870278
--- /dev/null
+++ b/src/hls/RTLBlockgenproof.v
@@ -0,0 +1,170 @@
+(*|
+..
+ Vericert: Verified high-level synthesis.
+ Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+================
+RTLBlockgenproof
+================
+
+.. coq:: none
+|*)
+
+Require compcert.backend.RTL.
+Require Import compcert.common.AST.
+Require Import compcert.common.Errors.
+Require Import compcert.common.Globalenvs.
+Require Import compcert.lib.Maps.
+
+Require Import vericert.common.Vericertlib.
+Require Import vericert.hls.RTLBlockInstr.
+Require Import vericert.hls.RTLBlock.
+Require Import vericert.hls.RTLBlockgen.
+
+#[local] Open Scope positive.
+
+(*|
+Defining a find block specification
+===================================
+
+Basically, it should be able to find the location of the block without using the
+``find_block`` function, so that this is more useful for the proofs. There are
+various different types of options that could come up though:
+
+1. The instruction is a standard instruction present inside of a basic block.
+2. The instruction is a standard instruction which ends with a ``goto``.
+3. The instruction is a control-flow instruction.
+
+For case number 1, there should exist a value in the list of instructions, such
+that the instructions match exactly, and the indices match as well. In the
+original code, this instruction must have been going from the current node to
+the node - 1.
+
+For case number 2, there should be an instruction at the right index again,
+however, this time there will also be a ``goto`` instruction in the control-flow
+part of the basic block.
+
+For case number 3, there should be a ``nop`` instruction in the basic block, and
+then the equivalent control-flow instruction ending the basic block.
+|*)
+
+Parameter find_block_spec : code -> node -> node -> Prop.
+
+Definition find_instr_spec (c: code) (n: node) (i: RTL.instruction)
+ (n': node) (i': instr) :=
+ find_block_spec c n n'
+ /\ exists il,
+ c ! n' = Some il
+ /\ nth_error il.(bb_body) (Pos.to_nat n - Pos.to_nat n')%nat = Some i'.
+
+(*|
+.. index::
+ pair: semantics; transl_code_spec
+
+Translation Specification
+-------------------------
+
+This specification should describe the translation that the unverified
+transformation performs. This should be proven from the validation of the
+transformation.
+|*)
+
+Variant transl_code_spec (c: RTL.code) (tc: code) :=
+| transl_code_standard_bb :
+ forall x x' i i',
+ c ! x = Some i ->
+ find_instr_spec tc x i x' i' ->
+ check_instr x i i' = true ->
+ transl_code_spec c tc
+| transl_code_standard_cf :
+ forall x x' i i' il,
+ c ! x = Some i ->
+ tc ! x' = Some il ->
+ find_instr_spec tc x i x' i' ->
+ check_cf_instr_body i i' = true ->
+ check_cf_instr i il.(bb_exit) = true ->
+ transl_code_spec c tc
+.
+
+Lemma transl_function_correct :
+ forall f tf,
+ transl_function f = OK tf ->
+ transl_code_spec f.(RTL.fn_code) tf.(fn_code).
+Proof. Admitted.
+
+Variant match_stackframe : RTL.stackframe -> stackframe -> Prop :=
+| match_stackframe_init :
+ forall a b,
+ match_stackframe a b.
+
+Variant match_states : RTL.state -> RTLBlock.state -> Prop :=
+| match_state :
+ forall stk stk' f tf sp pc rs m pc' ps
+ (TF: transl_function f = OK tf)
+ (PC: find_block_spec tf.(fn_code) pc pc')
+ (STK: Forall2 match_stackframe stk stk'),
+ match_states (RTL.State stk f sp pc rs m)
+ (State stk' tf sp pc' nil rs ps m).
+
+Definition match_prog (p: RTL.program) (tp: RTLBlock.program) :=
+ Linking.match_program (fun cu f tf => transl_fundef f = Errors.OK tf) eq p tp.
+
+Section CORRECTNESS.
+
+ Context (prog : RTL.program).
+ Context (tprog : RTLBlock.program).
+
+ Context (TRANSL : match_prog prog tprog).
+
+ Let ge : RTL.genv := Globalenvs.Genv.globalenv prog.
+ Let tge : genv := Globalenvs.Genv.globalenv tprog.
+
+ Lemma symbols_preserved:
+ forall (s: AST.ident), Genv.find_symbol tge s = Genv.find_symbol ge s.
+ Proof using TRANSL. intros. eapply (Genv.find_symbol_match TRANSL). Qed.
+
+ Lemma senv_preserved:
+ Senv.equiv (Genv.to_senv ge) (Genv.to_senv tge).
+ Proof using TRANSL. intros; eapply (Genv.senv_transf_partial TRANSL). Qed.
+ #[local] Hint Resolve senv_preserved : rtlgp.
+
+ Lemma transl_initial_states :
+ forall s1 : Smallstep.state (RTL.semantics prog),
+ Smallstep.initial_state (RTL.semantics prog) s1 ->
+ exists s2 : Smallstep.state (semantics tprog),
+ Smallstep.initial_state (semantics tprog) s2 /\ match_states s1 s2.
+ Proof. Admitted.
+
+ Lemma transl_final_states :
+ forall (s1 : Smallstep.state (RTL.semantics prog))
+ (s2 : Smallstep.state (semantics tprog))
+ (r : Integers.Int.int),
+ match_states s1 s2 ->
+ Smallstep.final_state (RTL.semantics prog) s1 r ->
+ Smallstep.final_state (semantics tprog) s2 r.
+ Proof. Admitted.
+
+ Theorem transf_program_correct:
+ Smallstep.forward_simulation (RTL.semantics prog)
+ (RTLBlock.semantics tprog).
+ Proof.
+ eapply Smallstep.forward_simulation_plus.
+ apply senv_preserved.
+ admit.
+ eauto using transl_final_states.
+ Admitted.
+
+End CORRECTNESS.
diff --git a/src/hls/RTLPar.v b/src/hls/RTLPar.v
index 4986cff..7ae563d 100644
--- a/src/hls/RTLPar.v
+++ b/src/hls/RTLPar.v
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020-2021 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ Require Import compcert.verilog.Op.
Require Import vericert.hls.RTLBlockInstr.
-Definition bb := list (list (list instr)).
+Definition bb := list (list instr).
Definition bblock := @bblock bb.
Definition code := @code bb.
@@ -46,15 +46,16 @@ Section RELSEM.
Context (ge: genv).
- Inductive step_instr_list: val -> instr_state -> list instr -> instr_state -> Prop :=
- | exec_RBcons:
- forall state i state' state'' instrs sp,
- step_instr ge sp state i state' ->
- step_instr_list sp state' instrs state'' ->
- step_instr_list sp state (i :: instrs) state''
- | exec_RBnil:
- forall state sp,
- step_instr_list sp state nil state.
+ Inductive step_instr_list:
+ val -> instr_state -> list instr -> instr_state -> Prop :=
+ | exec_RBcons:
+ forall state i state' state'' instrs sp,
+ step_instr ge sp state i state' ->
+ step_instr_list sp state' instrs state'' ->
+ step_instr_list sp state (i :: instrs) state''
+ | exec_RBnil:
+ forall state sp,
+ step_instr_list sp state nil state.
Inductive step_instr_seq (sp : val)
: instr_state -> list (list instr) -> instr_state -> Prop :=
@@ -68,7 +69,7 @@ Section RELSEM.
step_instr_seq sp state nil state.
Inductive step_instr_block (sp : val)
- : instr_state -> bb -> instr_state -> Prop :=
+ : instr_state -> list bb -> instr_state -> Prop :=
| exec_instr_block_cons:
forall state i state' state'' instrs,
step_instr_seq sp state i state' ->
@@ -80,11 +81,12 @@ Section RELSEM.
Inductive step: state -> trace -> state -> Prop :=
| exec_bblock:
- forall s f sp pc rs rs' m m' t s' bb pr pr',
+ forall s (f: function) sp pc rs rs' m m' t s' bb pr pr',
f.(fn_code)!pc = Some bb ->
- step_instr_block sp (mk_instr_state rs pr m) bb.(bb_body) (mk_instr_state rs' pr' m') ->
- step_cf_instr ge (State s f sp pc rs' pr' m') bb.(bb_exit) t s' ->
- step (State s f sp pc rs pr m) t s'
+ step_instr_block sp (mk_instr_state rs pr m) bb.(bb_body)
+ (mk_instr_state rs' pr' m') ->
+ step_cf_instr ge (State s f sp pc nil rs' pr' m') bb.(bb_exit) t s' ->
+ step (State s f sp pc nil rs pr m) t s'
| exec_function_internal:
forall s f args m m' stk,
Mem.alloc m 0 f.(fn_stacksize) = (m', stk) ->
@@ -93,6 +95,7 @@ Section RELSEM.
f
(Vptr stk Ptrofs.zero)
f.(fn_entrypoint)
+ nil
(init_regs args f.(fn_params))
(PMap.init false)
m')
@@ -104,7 +107,7 @@ Section RELSEM.
| exec_return:
forall res f sp pc rs s vres m pr,
step (Returnstate (Stackframe res f sp pc rs pr :: s) vres m)
- E0 (State s f sp pc (rs#res <- vres) pr m).
+ E0 (State s f sp pc nil (rs#res <- vres) pr m).
End RELSEM.
@@ -125,7 +128,11 @@ Definition semantics (p: program) :=
Semantics step (initial_state p) final_state (Genv.globalenv p).
Definition max_reg_bblock (m : positive) (pc : node) (bb : bblock) :=
- let max_body := fold_left (fun x l => fold_left (fun x' l' => fold_left max_reg_instr l' x') l x) bb.(bb_body) m in
+ let max_body :=
+ fold_left
+ (fun x l => fold_left (fun x' l' => fold_left max_reg_instr l' x') l x)
+ bb.(bb_body) m
+ in
max_reg_cfi max_body bb.(bb_exit).
Definition max_reg_function (f: function) :=
@@ -134,7 +141,9 @@ Definition max_reg_function (f: function) :=
(fold_left Pos.max f.(fn_params) 1%positive).
Definition max_pc_function (f: function) : positive :=
- PTree.fold (fun m pc i => (Pos.max m
- (pc + match Zlength i.(bb_body)
- with Z.pos p => p | _ => 1 end))%positive)
- f.(fn_code) 1%positive.
+ PTree.fold
+ (fun m pc i =>
+ (Pos.max m
+ (pc + match Zlength i.(bb_body)
+ with Z.pos p => p | _ => 1 end))%positive)
+ f.(fn_code) 1%positive.
diff --git a/src/hls/RTLParFU.v b/src/hls/RTLParFU.v
new file mode 100644
index 0000000..f0ceafd
--- /dev/null
+++ b/src/hls/RTLParFU.v
@@ -0,0 +1,389 @@
+(*
+ * Vericert: Verified high-level synthesis.
+ * Copyright (C) 2020-2021 Yann Herklotz <yann@yannherklotz.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *)
+
+Require Import compcert.backend.Registers.
+Require Import compcert.common.AST.
+Require Import compcert.common.Events.
+Require Import compcert.common.Globalenvs.
+Require Import compcert.common.Memory.
+Require Import compcert.common.Smallstep.
+Require Import compcert.common.Values.
+Require Import compcert.lib.Coqlib.
+Require Import compcert.lib.Integers.
+Require Import compcert.lib.Maps.
+Require Import compcert.verilog.Op.
+
+Require Import vericert.hls.FunctionalUnits.
+Require Import Predicate.
+Require Import Vericertlib.
+
+Definition node := positive.
+
+Inductive instr : Type :=
+| FUnop : instr
+| FUop : option pred_op -> operation -> list reg -> reg -> instr
+| FUread : positive -> positive -> reg -> instr
+| FUwrite : positive -> positive -> reg -> instr
+| FUsetpred : option pred_op -> condition -> list reg -> predicate -> instr.
+
+Inductive cf_instr : Type :=
+| FUcall : signature -> reg + ident -> list reg -> reg -> node -> cf_instr
+| FUtailcall : signature -> reg + ident -> list reg -> cf_instr
+| FUbuiltin : external_function -> list (builtin_arg reg) ->
+ builtin_res reg -> node -> cf_instr
+| FUcond : condition -> list reg -> node -> node -> cf_instr
+| FUjumptable : reg -> list node -> cf_instr
+| FUreturn : option reg -> cf_instr
+| FUgoto : node -> cf_instr
+| FUpred_cf : pred_op -> cf_instr -> cf_instr -> cf_instr.
+
+Fixpoint successors_instr (i : cf_instr) : list node :=
+ match i with
+ | FUcall sig ros args res s => s :: nil
+ | FUtailcall sig ros args => nil
+ | FUbuiltin ef args res s => s :: nil
+ | FUcond cond args ifso ifnot => ifso :: ifnot :: nil
+ | FUjumptable arg tbl => tbl
+ | FUreturn optarg => nil
+ | FUgoto n => n :: nil
+ | FUpred_cf p c1 c2 => concat (successors_instr c1 :: successors_instr c2 :: nil)
+ end.
+
+Definition max_reg_instr (m: positive) (i: instr) :=
+ match i with
+ | FUnop => m
+ | FUop p op args res =>
+ fold_left Pos.max args (Pos.max res m)
+ | FUread p1 p2 r => Pos.max m r
+ | FUwrite p1 p2 r => Pos.max m r
+ | FUsetpred p' c args p =>
+ fold_left Pos.max args m
+ end.
+
+Fixpoint max_reg_cfi (m : positive) (i : cf_instr) :=
+ match i with
+ | FUcall sig (inl r) args res s =>
+ fold_left Pos.max args (Pos.max r (Pos.max res m))
+ | FUcall sig (inr id) args res s =>
+ fold_left Pos.max args (Pos.max res m)
+ | FUtailcall sig (inl r) args =>
+ fold_left Pos.max args (Pos.max r m)
+ | FUtailcall sig (inr id) args =>
+ fold_left Pos.max args m
+ | FUbuiltin ef args res s =>
+ fold_left Pos.max (params_of_builtin_args args)
+ (fold_left Pos.max (params_of_builtin_res res) m)
+ | FUcond cond args ifso ifnot => fold_left Pos.max args m
+ | FUjumptable arg tbl => Pos.max arg m
+ | FUreturn None => m
+ | FUreturn (Some arg) => Pos.max arg m
+ | FUgoto n => m
+ | FUpred_cf p c1 c2 => Pos.max (max_reg_cfi m c1) (max_reg_cfi m c2)
+ end.
+
+Definition regset := Regmap.t val.
+Definition predset := PMap.t bool.
+
+Definition eval_predf (pr: predset) (p: pred_op) :=
+ sat_predicate p (fun x => pr !! (Pos.of_nat x)).
+
+#[global]
+ Instance eval_predf_Proper : Proper (eq ==> equiv ==> eq) eval_predf.
+Proof.
+ unfold Proper. simplify. unfold "==>".
+ intros.
+ unfold sat_equiv in *. intros. unfold eval_predf. subst. apply H0.
+Qed.
+
+#[local] Open Scope pred_op.
+
+Lemma eval_predf_Pand :
+ forall ps p p',
+ eval_predf ps (p ∧ p') = eval_predf ps p && eval_predf ps p'.
+Proof. unfold eval_predf; split; simplify; auto with bool. Qed.
+
+Lemma eval_predf_Por :
+ forall ps p p',
+ eval_predf ps (p ∨ p') = eval_predf ps p || eval_predf ps p'.
+Proof. unfold eval_predf; split; simplify; auto with bool. Qed.
+
+Lemma eval_predf_pr_equiv :
+ forall p ps ps',
+ (forall x, ps !! x = ps' !! x) ->
+ eval_predf ps p = eval_predf ps' p.
+Proof.
+ induction p; simplify; auto;
+ try (unfold eval_predf; simplify; repeat (destruct_match; []); inv Heqp0; rewrite <- H; auto);
+ [repeat rewrite eval_predf_Pand|repeat rewrite eval_predf_Por];
+ erewrite IHp1; try eassumption; erewrite IHp2; eauto.
+Qed.
+
+Fixpoint init_regs (vl: list val) (rl: list reg) {struct rl} : regset :=
+ match rl, vl with
+ | r1 :: rs, v1 :: vs => Regmap.set r1 v1 (init_regs vs rs)
+ | _, _ => Regmap.init Vundef
+ end.
+
+Definition bblock_body := list (list (list instr)).
+
+Record bblock : Type :=
+ mk_bblock {
+ bb_body: bblock_body;
+ bb_exit: cf_instr
+ }.
+
+Definition code: Type := PTree.t bblock.
+
+Record function: Type :=
+ mkfunction {
+ fn_sig: signature;
+ fn_params: list reg;
+ fn_stacksize: Z;
+ fn_code: code;
+ fn_funct_units: resources;
+ fn_entrypoint: node;
+ }.
+
+Definition fundef := AST.fundef function.
+Definition program := AST.program fundef unit.
+
+Definition funsig (fd: fundef) :=
+ match fd with
+ | Internal f => fn_sig f
+ | External ef => ef_sig ef
+ end.
+
+Inductive stackframe : Type :=
+| Stackframe:
+ forall (res: reg) (**r where to store the result *)
+ (f: function) (**r calling function *)
+ (sp: val) (**r stack pointer in calling function *)
+ (pc: node) (**r program point in calling function *)
+ (rs: regset) (**r register state in calling function *)
+ (pr: predset), (**r predicate state of the calling function *)
+ stackframe.
+
+Inductive state : Type :=
+| State:
+ forall (stack: list stackframe) (**r call stack *)
+ (f: function) (**r current function *)
+ (sp: val) (**r stack pointer *)
+ (pc: node) (**r current program point in [c] *)
+ (rs: regset) (**r register state *)
+ (pr: predset) (**r predicate register state *)
+ (m: mem), (**r memory state *)
+ state
+| Callstate:
+ forall (stack: list stackframe) (**r call stack *)
+ (f: fundef) (**r function to call *)
+ (args: list val) (**r arguments to the call *)
+ (m: mem), (**r memory state *)
+ state
+| Returnstate:
+ forall (stack: list stackframe) (**r call stack *)
+ (v: val) (**r return value for the call *)
+ (m: mem), (**r memory state *)
+ state.
+
+Record instr_state := mk_instr_state {
+ is_rs: regset;
+ is_ps: predset;
+ is_mem: mem;
+ }.
+
+Definition genv := Genv.t fundef unit.
+
+Section RELSEM.
+
+ Context (ge: genv).
+
+ Definition find_function
+ (ros: reg + ident) (rs: regset) : option fundef :=
+ match ros with
+ | inl r => Genv.find_funct ge rs#r
+ | inr symb =>
+ match Genv.find_symbol ge symb with
+ | None => None
+ | Some b => Genv.find_funct_ptr ge b
+ end
+ end.
+
+ Inductive eval_pred: option pred_op -> instr_state -> instr_state -> instr_state -> Prop :=
+ | eval_pred_true:
+ forall i i' p,
+ eval_predf (is_ps i) p = true ->
+ eval_pred (Some p) i i' i'
+ | eval_pred_false:
+ forall i i' p,
+ eval_predf (is_ps i) p = false ->
+ eval_pred (Some p) i i' i
+ | eval_pred_none:
+ forall i i', eval_pred None i i' i.
+
+ Inductive step_instr: val -> instr_state -> instr -> instr_state -> Prop :=
+ | exec_FUnop:
+ forall sp ist,
+ step_instr sp ist FUnop ist
+ | exec_FUop:
+ forall op v res args rs m sp p ist pr,
+ eval_operation ge sp op rs##args m = Some v ->
+ eval_pred p (mk_instr_state rs pr m) (mk_instr_state (rs#res <- v) pr m) ist ->
+ step_instr sp (mk_instr_state rs pr m) (FUop p op args res) ist
+ | exec_FUsetpred:
+ forall sp rs pr m p c b args p' ist,
+ Op.eval_condition c rs##args m = Some b ->
+ eval_pred p' (mk_instr_state rs pr m) (mk_instr_state rs (pr#p <- b) m) ist ->
+ step_instr sp (mk_instr_state rs pr m) (FUsetpred p' c args p) ist.
+
+ Inductive step_instr_list: val -> instr_state -> list instr -> instr_state -> Prop :=
+ | exec_RBcons:
+ forall state i state' state'' instrs sp,
+ step_instr sp state i state' ->
+ step_instr_list sp state' instrs state'' ->
+ step_instr_list sp state (i :: instrs) state''
+ | exec_RBnil:
+ forall state sp,
+ step_instr_list sp state nil state.
+
+ Inductive step_instr_seq (sp : val)
+ : instr_state -> list (list instr) -> instr_state -> Prop :=
+ | exec_instr_seq_cons:
+ forall state i state' state'' instrs,
+ step_instr_list sp state i state' ->
+ step_instr_seq sp state' instrs state'' ->
+ step_instr_seq sp state (i :: instrs) state''
+ | exec_instr_seq_nil:
+ forall state,
+ step_instr_seq sp state nil state.
+
+ Inductive step_instr_block (sp : val)
+ : instr_state -> bblock_body -> instr_state -> Prop :=
+ | exec_instr_block_cons:
+ forall state i state' state'' instrs,
+ step_instr_seq sp state i state' ->
+ step_instr_block sp state' instrs state'' ->
+ step_instr_block sp state (i :: instrs) state''
+ | exec_instr_block_nil:
+ forall state,
+ step_instr_block sp state nil state.
+
+ Inductive step_cf_instr: state -> cf_instr -> trace -> state -> Prop :=
+ | exec_FUcall:
+ forall s f sp rs m res fd ros sig args pc pc' pr,
+ find_function ros rs = Some fd ->
+ funsig fd = sig ->
+ step_cf_instr (State s f sp pc rs pr m) (FUcall sig ros args res pc')
+ E0 (Callstate (Stackframe res f sp pc' rs pr :: s) fd rs##args m)
+ | exec_FUtailcall:
+ forall s f stk rs m sig ros args fd m' pc pr,
+ find_function ros rs = Some fd ->
+ funsig fd = sig ->
+ Mem.free m stk 0 f.(fn_stacksize) = Some m' ->
+ step_cf_instr (State s f (Vptr stk Ptrofs.zero) pc rs pr m) (FUtailcall sig ros args)
+ E0 (Callstate s fd rs##args m')
+ | exec_FUbuiltin:
+ forall s f sp rs m ef args res pc' vargs t vres m' pc pr,
+ eval_builtin_args ge (fun r => rs#r) sp m args vargs ->
+ external_call ef ge vargs m t vres m' ->
+ step_cf_instr (State s f sp pc rs pr m) (FUbuiltin ef args res pc')
+ t (State s f sp pc' (regmap_setres res vres rs) pr m')
+ | exec_FUcond:
+ forall s f sp rs m cond args ifso ifnot b pc pc' pr,
+ eval_condition cond rs##args m = Some b ->
+ pc' = (if b then ifso else ifnot) ->
+ step_cf_instr (State s f sp pc rs pr m) (FUcond cond args ifso ifnot)
+ E0 (State s f sp pc' rs pr m)
+ | exec_FUjumptable:
+ forall s f sp rs m arg tbl n pc pc' pr,
+ rs#arg = Vint n ->
+ list_nth_z tbl (Int.unsigned n) = Some pc' ->
+ step_cf_instr (State s f sp pc rs pr m) (FUjumptable arg tbl)
+ E0 (State s f sp pc' rs pr m)
+ | exec_FUreturn:
+ forall s f stk rs m or pc m' pr,
+ Mem.free m stk 0 f.(fn_stacksize) = Some m' ->
+ step_cf_instr (State s f (Vptr stk Ptrofs.zero) pc rs pr m) (FUreturn or)
+ E0 (Returnstate s (regmap_optget or Vundef rs) m')
+ | exec_FUgoto:
+ forall s f sp pc rs pr m pc',
+ step_cf_instr (State s f sp pc rs pr m) (FUgoto pc') E0 (State s f sp pc' rs pr m)
+ | exec_FUpred_cf:
+ forall s f sp pc rs pr m cf1 cf2 st' p t,
+ step_cf_instr (State s f sp pc rs pr m) (if eval_predf pr p then cf1 else cf2) t st' ->
+ step_cf_instr (State s f sp pc rs pr m) (FUpred_cf p cf1 cf2) t st'.
+
+ Inductive step: state -> trace -> state -> Prop :=
+ | exec_bblock:
+ forall s f sp pc rs rs' m m' t s' bb pr pr',
+ f.(fn_code)!pc = Some bb ->
+ step_instr_block sp (mk_instr_state rs pr m) bb.(bb_body) (mk_instr_state rs' pr' m') ->
+ step_cf_instr (State s f sp pc rs' pr' m') bb.(bb_exit) t s' ->
+ step (State s f sp pc rs pr m) t s'
+ | exec_function_internal:
+ forall s f args m m' stk,
+ Mem.alloc m 0 f.(fn_stacksize) = (m', stk) ->
+ step (Callstate s (Internal f) args m)
+ E0 (State s
+ f
+ (Vptr stk Ptrofs.zero)
+ f.(fn_entrypoint)
+ (init_regs args f.(fn_params))
+ (PMap.init false) m')
+ | exec_function_external:
+ forall s ef args res t m m',
+ external_call ef ge args m t res m' ->
+ step (Callstate s (External ef) args m)
+ t (Returnstate s res m')
+ | exec_return:
+ forall res f sp pc rs s vres m pr,
+ step (Returnstate (Stackframe res f sp pc rs pr :: s) vres m)
+ E0 (State s f sp pc (rs#res <- vres) pr m).
+
+End RELSEM.
+
+Inductive initial_state (p: program): state -> Prop :=
+| initial_state_intro: forall b f m0,
+ let ge := Genv.globalenv p in
+ Genv.init_mem p = Some m0 ->
+ Genv.find_symbol ge p.(prog_main) = Some b ->
+ Genv.find_funct_ptr ge b = Some f ->
+ funsig f = signature_main ->
+ initial_state p (Callstate nil f nil m0).
+
+Inductive final_state: state -> int -> Prop :=
+| final_state_intro: forall r m,
+ final_state (Returnstate nil (Vint r) m) r.
+
+Definition semantics (p: program) :=
+ Semantics step (initial_state p) final_state (Genv.globalenv p).
+
+Definition max_reg_bblock (m : positive) (pc : node) (bb : bblock) :=
+ let max_body := fold_left (fun x l => fold_left (fun x' l' => fold_left max_reg_instr l' x') l x) bb.(bb_body) m in
+ max_reg_cfi max_body bb.(bb_exit).
+
+Definition max_reg_function (f: function) :=
+ Pos.max
+ (PTree.fold max_reg_bblock f.(fn_code) 1%positive)
+ (Pos.max (fold_left Pos.max f.(fn_params) 1%positive)
+ (max_reg_resources f.(fn_funct_units))).
+
+Definition max_pc_function (f: function) : positive :=
+ PTree.fold (fun m pc i => (Pos.max m
+ (pc + match Zlength i.(bb_body)
+ with Z.pos p => p | _ => 1 end))%positive)
+ f.(fn_code) 1%positive.
diff --git a/src/hls/RTLParFUgen.v b/src/hls/RTLParFUgen.v
new file mode 100644
index 0000000..a104056
--- /dev/null
+++ b/src/hls/RTLParFUgen.v
@@ -0,0 +1,177 @@
+(*
+ * Vericert: Verified high-level synthesis.
+ * Copyright (C) 2021 Yann Herklotz <yann@yannherklotz.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *)
+
+Require Import Coq.micromega.Lia.
+
+Require Import compcert.common.AST.
+Require Import compcert.common.Errors.
+Require compcert.common.Globalenvs.
+Require Import compcert.lib.Integers.
+Require Import compcert.lib.Maps.
+
+Require Import vericert.common.Statemonad.
+Require Import vericert.common.Vericertlib.
+Require Import vericert.hls.AssocMap.
+Require Import vericert.hls.Predicate.
+Require Import vericert.hls.ValueInt.
+Require Import vericert.hls.Verilog.
+Require Import vericert.hls.RTLBlockInstr.
+Require Import vericert.hls.RTLPar.
+Require Import vericert.hls.RTLParFU.
+Require Import vericert.hls.FunctionalUnits.
+
+#[local] Open Scope error_monad_scope.
+
+Definition update {A: Type} (i: positive) (f: option A -> A) (pt: PTree.t A) :=
+ PTree.set i (f (pt ! i)) pt.
+
+Definition add_instr (instr_: instr) x :=
+ match x with Some i => instr_ :: i | None => instr_ :: nil end.
+
+Definition transl_instr (res: resources) (cycle: positive) (i: RTLBlockInstr.instr)
+ (li: Errors.res (list instr * PTree.t (list instr))):
+ Errors.res (list instr * PTree.t (list instr)) :=
+ do (instr_list, d_tree) <- li;
+ match i with
+ | RBnop => Errors.OK (FUnop :: instr_list, d_tree)
+ | RBop po op args d => Errors.OK (FUop po op args d :: instr_list, d_tree)
+ | RBload po chunk addr args d =>
+ match get_ram 0 res with
+ | Some (ri, r) =>
+ Errors.OK (FUop po Op.Onot (ram_u_en r::nil) (ram_u_en r)
+ :: FUop po (Op.Ointconst (Int.repr 0)) nil (ram_wr_en r)
+ :: FUop po (Op.Olea addr) args (ram_addr r)
+ :: FUop po (Op.Oshruimm (Int.repr 2)) ((ram_addr r)::nil) (ram_addr r)
+ :: instr_list, update (Pos.pred cycle)
+ (add_instr (FUop po Op.Omove (ram_d_out r::nil) d))
+ d_tree)
+ | _ => Errors.Error (Errors.msg "Could not find RAM")
+ end
+ | RBstore po chunk addr args d =>
+ match get_ram 0 res with
+ | Some (ri, r) =>
+ Errors.OK (FUop po Op.Onot (ram_u_en r::nil) (ram_u_en r)
+ :: FUop po (Op.Ointconst (Int.repr 1)) nil (ram_wr_en r)
+ :: FUop po Op.Omove (d::nil) (ram_d_in r)
+ :: FUop po (Op.Olea addr) args (ram_addr r)
+ :: FUop po (Op.Oshruimm (Int.repr 2)) ((ram_addr r)::nil) (ram_addr r)
+ :: instr_list, d_tree)
+ | _ => Errors.Error (Errors.msg "Could not find RAM")
+ end
+ | RBsetpred op c args p => Errors.OK (FUsetpred op c args p :: instr_list, d_tree)
+ end.
+
+Fixpoint transl_cf_instr (i: RTLBlockInstr.cf_instr): RTLParFU.cf_instr :=
+ match i with
+ | RBcall sig r args d n => FUcall sig r args d n
+ | RBtailcall sig r args => FUtailcall sig r args
+ | RBbuiltin ef args r n => FUbuiltin ef args r n
+ | RBcond c args n1 n2 => FUcond c args n1 n2
+ | RBjumptable r ns => FUjumptable r ns
+ | RBreturn r => FUreturn r
+ | RBgoto n => FUgoto n
+ | RBpred_cf po c1 c2 => FUpred_cf po (transl_cf_instr c1) (transl_cf_instr c2)
+ end.
+
+Definition list_split {A:Type} (l: list (Z * A)) : (list (Z * A)) * (list (Z * A)) :=
+ (filter (fun x => Z.eqb 0 (fst x)) l,
+ map (fun x => (Z.pred (fst x), snd x)) (filter (fun x => negb (Z.eqb 0 (fst x))) l)).
+
+Fixpoint map_error {A B : Type} (f : A -> res B) (l : list A) {struct l} : res (list B) :=
+ match l with
+ | nil => OK nil
+ | x::xs =>
+ do y <- f x ;
+ do ys <- map_error f xs ;
+ OK (y::ys)
+ end.
+
+Definition transl_op_chain_block (res: resources) (cycle: positive) (instrs: list RTLBlockInstr.instr)
+ (state: Errors.res (list (list instr) * PTree.t (list instr)))
+ : Errors.res (list (list instr) * PTree.t (list instr)) :=
+ do (li, tr) <- state;
+ do (li', tr') <- fold_right (transl_instr res cycle) (OK (nil, tr)) instrs;
+ OK (li' :: li, tr').
+
+(*Compute transl_op_chain_block initial_resources 10%nat (RBop None (Op.Ointconst (Int.repr 1)) nil 1%positive::RBnop::RBnop::RBnop::nil) (OK (nil, PTree.empty _)).*)
+
+Definition transl_par_block (res: resources) (cycle: positive) (instrs: list (list RTLBlockInstr.instr))
+ (state: Errors.res (list (list (list instr)) * PTree.t (list instr)))
+ : Errors.res (list (list (list instr)) * PTree.t (list instr)) :=
+ do (li, tr) <- state;
+ do (li', tr') <- fold_right (transl_op_chain_block res cycle) (OK (nil, tr)) instrs;
+ OK (li' :: li, tr').
+
+(*Compute transl_par_block initial_resources 10%nat ((RBop None (Op.Ointconst (Int.repr 1)) nil 1%positive::RBnop::nil)::(RBop None (Op.Ointconst (Int.repr 2)) nil 2%positive::RBnop::nil)::nil) (OK (((FUnop::nil)::nil)::nil, PTree.empty _)).*)
+
+Definition transl_seq_block (res: resources) (b: list (list RTLBlockInstr.instr))
+ (a: Errors.res (list (list (list instr)) * PTree.t (list instr) * positive)) :=
+ do (litr, n) <- a;
+ let (li, tr) := litr in
+ do (li', tr') <- transl_par_block res n b (OK (li, tr));
+ OK (li', tr', (n+1)%positive).
+
+Definition insert_extra (pt: PTree.t (list instr)) (curr: list (list instr))
+ (cycle_bb: (positive * list (list (list instr)))) :=
+ let (cycle, bb) := cycle_bb in
+ match pt ! cycle with
+ | Some instrs => ((cycle + 1)%positive, (curr ++ (map (fun x => x :: nil) instrs)) :: bb)
+ | None => ((cycle + 1)%positive, curr :: bb)
+ end.
+
+Definition transl_bb (res: resources) (bb: list RTLPar.bb): Errors.res RTLParFU.bblock_body :=
+ do (litr, n) <- fold_right (transl_seq_block res) (OK (nil, PTree.empty _, 1%positive)) bb;
+ let (li, tr) := litr in
+ OK (snd (fold_right (insert_extra tr) (1%positive, nil) li)).
+
+Definition transl_bblock (res: resources) (bb: RTLPar.bblock): Errors.res bblock :=
+ do bb' <- transl_bb res (RTLBlockInstr.bb_body bb);
+ OK (mk_bblock bb' (transl_cf_instr (RTLBlockInstr.bb_exit bb))).
+
+Definition error_map_ptree {A B: Type} (f: positive -> A -> res B) (pt: PTree.t A) :=
+ do ptl' <- map_error (fun x => do x' <- uncurry f x; OK (fst x, x')) (PTree.elements pt);
+ OK (PTree_Properties.of_list ptl').
+
+Definition transl_code (fu: resources) (c: RTLPar.code): res code :=
+ error_map_ptree (fun _ => transl_bblock fu) c.
+
+Definition transl_function (f: RTLPar.function): Errors.res RTLParFU.function :=
+ let max := RTLPar.max_reg_function f in
+ let fu := set_res (Ram (mk_ram
+ (Z.to_nat (RTLBlockInstr.fn_stacksize f))
+ (max+1)%positive
+ (max+3)%positive
+ (max+7)%positive
+ (max+2)%positive
+ (max+6)%positive
+ (max+4)%positive
+ (max+5)%positive
+ )) initial_resources in
+ do c' <- transl_code fu (RTLBlockInstr.fn_code f);
+ Errors.OK (mkfunction (RTLBlockInstr.fn_sig f)
+ (RTLBlockInstr.fn_params f)
+ (RTLBlockInstr.fn_stacksize f)
+ c'
+ fu
+ (RTLBlockInstr.fn_entrypoint f)).
+
+Definition transl_fundef p :=
+ transf_partial_fundef transl_function p.
+
+Definition transl_program (p : RTLPar.program) : Errors.res RTLParFU.program :=
+ transform_partial_program transl_fundef p.
diff --git a/src/hls/RTLPargen.v b/src/hls/RTLPargen.v
index ae4412b..214da6f 100644
--- a/src/hls/RTLPargen.v
+++ b/src/hls/RTLPargen.v
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020-2021 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,26 +34,25 @@ Require Import vericert.hls.Predicate.
Require Import vericert.hls.Abstr.
Import NE.NonEmptyNotation.
-(*|
-=================
-RTLPar Generation
-=================
-|*)
-
#[local] Open Scope positive.
#[local] Open Scope forest.
#[local] Open Scope pred_op.
(*|
+=========
+RTLPargen
+=========
+
Abstract Computations
=====================
-Define the abstract computation using the ``update`` function, which will set each register to its
-symbolic value. First we need to define a few helper functions to correctly translate the
-predicates.
+Define the abstract computation using the [update] function, which will set each
+register to its symbolic value. First we need to define a few helper functions
+to correctly translate the predicates.
|*)
-Fixpoint list_translation (l : list reg) (f : forest) {struct l} : list pred_expr :=
+Fixpoint list_translation (l : list reg) (f : forest) {struct l}
+ : list pred_expr :=
match l with
| nil => nil
| i :: l => (f # (Reg i)) :: (list_translation l f)
@@ -77,7 +76,8 @@ Definition merge'' x :=
| ((a, e), (b, el)) => (merge''' a b, Econs e el)
end.
-Definition map_pred_op {A B} (pf: option pred_op * (A -> B)) (pa: option pred_op * A): option pred_op * B :=
+Definition map_pred_op {A B} (pf: option pred_op * (A -> B))
+ (pa: option pred_op * A): option pred_op * B :=
match pa, pf with
| (p, a), (p', f) => (merge''' p p', f a)
end.
@@ -86,8 +86,8 @@ Definition predicated_prod {A B: Type} (p1: predicated A) (p2: predicated B) :=
NE.map (fun x => match x with ((a, b), (c, d)) => (Pand a c, (b, d)) end)
(NE.non_empty_prod p1 p2).
-Definition predicated_map {A B: Type} (f: A -> B) (p: predicated A): predicated B :=
- NE.map (fun x => (fst x, f (snd x))) p.
+Definition predicated_map {A B: Type} (f: A -> B) (p: predicated A)
+ : predicated B := NE.map (fun x => (fst x, f (snd x))) p.
(*map (fun x => (fst x, Econs (snd x) Enil)) pel*)
Definition merge' (pel: pred_expr) (tpel: predicated expression_list) :=
@@ -99,16 +99,20 @@ Fixpoint merge (pel: list pred_expr): predicated expression_list :=
| a :: b => merge' a (merge b)
end.
-Definition map_predicated {A B} (pf: predicated (A -> B)) (pa: predicated A): predicated B :=
+Definition map_predicated {A B} (pf: predicated (A -> B)) (pa: predicated A)
+ : predicated B :=
predicated_map (fun x => (fst x) (snd x)) (predicated_prod pf pa).
-Definition predicated_apply1 {A B} (pf: predicated (A -> B)) (pa: A): predicated B :=
+Definition predicated_apply1 {A B} (pf: predicated (A -> B)) (pa: A)
+ : predicated B :=
NE.map (fun x => (fst x, (snd x) pa)) pf.
-Definition predicated_apply2 {A B C} (pf: predicated (A -> B -> C)) (pa: A) (pb: B): predicated C :=
+Definition predicated_apply2 {A B C} (pf: predicated (A -> B -> C)) (pa: A)
+ (pb: B): predicated C :=
NE.map (fun x => (fst x, (snd x) pa pb)) pf.
-Definition predicated_apply3 {A B C D} (pf: predicated (A -> B -> C -> D)) (pa: A) (pb: B) (pc: C): predicated D :=
+Definition predicated_apply3 {A B C D} (pf: predicated (A -> B -> C -> D))
+ (pa: A) (pb: B) (pc: C): predicated D :=
NE.map (fun x => (fst x, (snd x) pa pb pc)) pf.
Definition predicated_from_opt {A: Type} (p: option pred_op) (a: A) :=
@@ -132,23 +136,34 @@ Fixpoint NEapp {A} (l m: NE.non_empty A) :=
| a ::| b => a ::| NEapp b m
end.
-Definition app_predicated {A: Type} (a b: predicated A) :=
+Definition app_predicated' {A: Type} (a b: predicated A) :=
let negation := ¬ (NEfold_left (fun a b => a ∨ (fst b)) b ⟂) in
- NEapp (NE.map (fun x => (negation ∧ (fst x), snd x)) a) b.
+ NEapp (NE.map (fun x => (negation ∧ fst x, snd x)) a) b.
+
+Definition app_predicated {A: Type} (p: option pred_op) (a b: predicated A) :=
+ match p with
+ | Some p' => NEapp (NE.map (fun x => (¬ p' ∧ fst x, snd x)) a)
+ (NE.map (fun x => (p' ∧ fst x, snd x)) b)
+ | None => b
+ end.
+
+Definition pred_ret {A: Type} (a: A) : predicated A :=
+ NE.singleton (T, a).
(*|
Update Function
---------------
-The ``update`` function will generate a new forest given an existing forest and a new instruction,
-so that it can evaluate a symbolic expression by folding over a list of instructions. The main
-problem is that predicates need to be merged as well, so that:
+The ``update`` function will generate a new forest given an existing forest and
+a new instruction, so that it can evaluate a symbolic expression by folding over
+a list of instructions. The main problem is that predicates need to be merged
+as well, so that:
1. The predicates are *independent*.
2. The expression assigned to the register should still be correct.
-This is done by multiplying the predicates together, and assigning the negation of the expression to
-the other predicates.
+This is done by multiplying the predicates together, and assigning the negation
+of the expression to the other predicates.
|*)
Definition update (f : forest) (i : instr) : forest :=
@@ -156,34 +171,38 @@ Definition update (f : forest) (i : instr) : forest :=
| RBnop => f
| RBop p op rl r =>
f # (Reg r) <-
- (app_predicated
+ (app_predicated p
(f # (Reg r))
- (map_predicated (predicated_from_opt p (Eop op)) (merge (list_translation rl f))))
+ (map_predicated (pred_ret (Eop op)) (merge (list_translation rl f))))
| RBload p chunk addr rl r =>
f # (Reg r) <-
- (app_predicated
+ (app_predicated p
(f # (Reg r))
(map_predicated
- (map_predicated (predicated_from_opt p (Eload chunk addr)) (merge (list_translation rl f)))
+ (map_predicated (pred_ret (Eload chunk addr))
+ (merge (list_translation rl f)))
(f # Mem)))
| RBstore p chunk addr rl r =>
f # Mem <-
- (app_predicated
- (f # (Reg r))
+ (app_predicated p
+ (f # Mem)
(map_predicated
(map_predicated
- (predicated_apply2 (map_predicated (predicated_from_opt p Estore) (f # (Reg r))) chunk addr)
+ (predicated_apply2 (map_predicated (pred_ret Estore)
+ (f # (Reg r))) chunk addr)
(merge (list_translation rl f))) (f # Mem)))
| RBsetpred p' c args p =>
f # (Pred p) <-
- (app_predicated
+ (app_predicated p'
(f # (Pred p))
- (map_predicated (predicated_from_opt p' (Esetpred c)) (merge (list_translation args f))))
+ (map_predicated (pred_ret (Esetpred c))
+ (merge (list_translation args f))))
end.
(*|
-Implementing which are necessary to show the correctness of the translation validation by showing
-that there aren't any more effects in the resultant RTLPar code than in the RTLBlock code.
+Implementing which are necessary to show the correctness of the translation
+validation by showing that there aren't any more effects in the resultant RTLPar
+code than in the RTLBlock code.
Get a sequence from the basic block.
|*)
@@ -195,19 +214,20 @@ Fixpoint abstract_sequence (f : forest) (b : list instr) : forest :=
end.
(*|
-Check equivalence of control flow instructions. As none of the basic blocks should have been moved,
-none of the labels should be different, meaning the control-flow instructions should match exactly.
+Check equivalence of control flow instructions. As none of the basic blocks
+should have been moved, none of the labels should be different, meaning the
+control-flow instructions should match exactly.
|*)
Definition check_control_flow_instr (c1 c2: cf_instr) : bool :=
if cf_instr_eq c1 c2 then true else false.
(*|
-We define the top-level oracle that will check if two basic blocks are equivalent after a scheduling
-transformation.
+We define the top-level oracle that will check if two basic blocks are
+equivalent after a scheduling transformation.
|*)
-Definition empty_trees (bb: RTLBlock.bb) (bbt: RTLPar.bb) : bool :=
+Definition empty_trees (bb: list RTLBlock.bb) (bbt: list RTLPar.bb) : bool :=
match bb with
| nil =>
match bbt with
@@ -253,7 +273,8 @@ Top-level Functions
Parameter schedule : RTLBlock.function -> RTLPar.function.
-Definition transl_function (f: RTLBlock.function) : Errors.res RTLPar.function :=
+Definition transl_function (f: RTLBlock.function)
+ : Errors.res RTLPar.function :=
let tfcode := fn_code (schedule f) in
if check_scheduled_trees f.(fn_code) tfcode then
Errors.OK (mkfunction f.(fn_sig)
@@ -262,7 +283,8 @@ Definition transl_function (f: RTLBlock.function) : Errors.res RTLPar.function :
tfcode
f.(fn_entrypoint))
else
- Errors.Error (Errors.msg "RTLPargen: Could not prove the blocks equivalent.").
+ Errors.Error
+ (Errors.msg "RTLPargen: Could not prove the blocks equivalent.").
Definition transl_fundef := transf_partial_fundef transl_function.
diff --git a/src/hls/RTLPargenproof.v b/src/hls/RTLPargenproof.v
index df0615a..215aef5 100644
--- a/src/hls/RTLPargenproof.v
+++ b/src/hls/RTLPargenproof.v
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2021 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,6 +37,17 @@ Require Import vericert.hls.Abstr.
#[local] Open Scope forest.
#[local] Open Scope pred_op.
+(*|
+==============
+RTLPargenproof
+==============
+
+RTLBlock to abstract translation
+================================
+
+Correctness of translation from RTLBlock to the abstract interpretation language.
+|*)
+
(*Definition is_regs i := match i with mk_instr_state rs _ => rs end.
Definition is_mem i := match i with mk_instr_state _ m => m end.
@@ -46,13 +57,6 @@ Inductive state_lessdef : instr_state -> instr_state -> Prop :=
(forall x, rs1 !! x = rs2 !! x) ->
state_lessdef (mk_instr_state rs1 m1) (mk_instr_state rs2 m1).
-(*|
-RTLBlock to abstract translation
---------------------------------
-
-Correctness of translation from RTLBlock to the abstract interpretation language.
-|*)
-
Ltac inv_simp :=
repeat match goal with
| H: exists _, _ |- _ => inv H
@@ -742,7 +746,11 @@ Lemma sem_update :
match_states st' st''' ->
@step_instr A ge sp st''' x st'' ->
exists tst, sem (mk_ctx st sp ge) (update f x) tst /\ match_states st'' tst.
-Proof. Admitted.
+Proof.
+ intros. destruct x.
+ - inv H1. econstructor. simplify. eauto. symmetry; auto.
+ - inv H1. inv H0. econstructor.
+ Admitted.
Lemma rtlblock_trans_correct :
forall bb ge sp st st',
@@ -804,8 +812,8 @@ Inductive match_states: RTLBlock.state -> RTLPar.state -> Prop :=
(STACKS: list_forall2 match_stackframes sf sf')
(REG: forall x, rs !! x = rs' !! x)
(REG: forall x, ps !! x = ps' !! x),
- match_states (State sf f sp pc rs ps m)
- (State sf' tf sp pc rs' ps' m)
+ match_states (State sf f sp pc nil rs ps m)
+ (State sf' tf sp pc nil rs' ps' m)
| match_returnstate:
forall stack stack' v m
(STACKS: list_forall2 match_stackframes stack stack'),
@@ -1092,7 +1100,7 @@ Proof. induction 2; try rewrite H; eauto with barg. Qed.
eauto. eauto. simplify. eauto. eauto. }
{ unfold bind in *. inv TRANSL0. clear Learn. inv H0. destruct_match; crush.
inv H2. unfold transl_function in Heqr. destruct_match; crush.
- inv Heqr.
+ inv Heqr.
repeat econstructor; eauto.
unfold bind in *. destruct_match; crush. }
{ inv TRANSL0. repeat econstructor; eauto using Events.external_call_symbols_preserved, symbols_preserved, senv_preserved, Events.E0_right. }
diff --git a/src/hls/Sat.v b/src/hls/Sat.v
index b7596f6..428c176 100644
--- a/src/hls/Sat.v
+++ b/src/hls/Sat.v
@@ -119,7 +119,6 @@ Lemma satLit_contra : forall s l a cl,
-> satClause cl a.
unfold satLit, upd; simpl; intros.
destruct (eq_nat_dec (snd l) (snd l)); intuition.
- assert False; intuition.
Qed.
#[local] Hint Resolve satLit_contra : core.
@@ -287,6 +286,7 @@ Lemma unitClauseTrue : forall l a fm,
induction fm; intuition.
inversion H.
inversion H; subst; simpl in H0; intuition.
+ apply IHfm; eauto. inv H0. eauto.
Qed.
#[local] Hint Resolve unitClauseTrue : core.
diff --git a/src/hls/Schedule.ml b/src/hls/Schedule.ml
index c5443c7..70395e7 100644
--- a/src/hls/Schedule.ml
+++ b/src/hls/Schedule.ml
@@ -1,6 +1,6 @@
(*
* Vericert: Verified high-level synthesis.
- * Copyright (C) 2020 Yann Herklotz <yann@yannherklotz.com>
+ * Copyright (C) 2020-2022 Yann Herklotz <yann@yannherklotz.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -289,6 +289,7 @@ let comb_delay = function
| _ -> 1
let pipeline_stages = function
+ | RBload _ -> 2
| RBop (_, op, _, _) ->
(match op with
| Odiv -> 32
@@ -304,7 +305,7 @@ let add_dep map i tree dfg curr =
| None -> dfg
| Some ip ->
let ipv = (List.nth map ip) in
- DFG.add_edge_e dfg (ipv, comb_delay (snd ipv), List.nth map i)
+ DFG.add_edge_e dfg (ipv, comb_delay (snd (List.nth map i)), List.nth map i)
(** This function calculates the dependencies of each instruction. The nodes correspond to previous
registers that were allocated and show which instruction caused it.
@@ -327,6 +328,7 @@ let accumulate_RAW_deps map dfg curr =
match curr with
| RBop (op, _, rs, dst) -> acc_dep_instruction rs dst
| RBload (op, _mem, _addr, rs, dst) -> acc_dep_instruction rs dst
+ | RBsetpred (_op, _mem, rs, _p) -> acc_dep_instruction_nodst rs
| RBstore (op, _mem, _addr, rs, src) -> acc_dep_instruction_nodst (src :: rs)
| _ -> (i + 1, dst_map, graph)
@@ -407,7 +409,7 @@ let accumulate_WAW_mem_deps instrs dfg curri =
| RBstore (_, _, _, _, _) -> (
match next_store 0 (take i instrs |> List.rev) with
| None -> dfg
- | Some d -> DFG.add_edge dfg (gen_vertex instrs (i - d - 1)) (gen_vertex instrs i) )
+ | Some d -> DFG.add_edge dfg (gen_vertex instrs (i - d - 1)) (gen_vertex instrs i))
| _ -> dfg
(** Predicate dependencies. *)
@@ -424,6 +426,7 @@ let get_predicate = function
| RBop (p, _, _, _) -> p
| RBload (p, _, _, _, _) -> p
| RBstore (p, _, _, _, _) -> p
+ | RBsetpred (p, _, _, _) -> p
| _ -> None
let rec next_setpred p i = function
@@ -447,6 +450,7 @@ let rec next_preduse p i instr=
| RBload (Some p', _, _, _, _) :: rst -> next p' rst
| RBstore (Some p', _, _, _, _) :: rst -> next p' rst
| RBop (Some p', _, _, _) :: rst -> next p' rst
+ | RBsetpred (Some p', _, _, _) :: rst -> next p' rst
| _ :: rst -> next_load (i + 1) rst
let accumulate_RAW_pred_deps instrs dfg curri =
@@ -571,6 +575,18 @@ let gather_bb_constraints debug bb =
let encode_var bbn n i = { sv_type = VarType (bbn, n); sv_num = i }
let encode_bb bbn i = { sv_type = BBType bbn; sv_num = i }
+let add_initial_sv n dfg constr =
+ let add_initial_sv' (i, instr) g =
+ let pipes = pipeline_stages instr in
+ if pipes > 0 then
+ List.init pipes (fun i' -> i')
+ |> List.fold_left (fun g i' ->
+ G.add_edge_e g (encode_var n i i', -1, encode_var n i (i'+1))
+ ) g
+ else g
+ in
+ DFG.fold_vertex add_initial_sv' dfg constr
+
let add_super_nodes n dfg =
DFG.fold_vertex (function v1 -> fun g ->
(if DFG.in_degree dfg v1 = 0
@@ -578,12 +594,14 @@ let add_super_nodes n dfg =
else g) |>
(fun g' ->
if DFG.out_degree dfg v1 = 0
- then G.add_edge_e g' (encode_var n (fst v1) 0, 0, encode_bb n 1)
+ then G.add_edge_e g' (encode_var n (fst v1) (pipeline_stages (snd v1)),
+ 0, encode_bb n 1)
else g')) dfg
let add_data_deps n =
- DFG.fold_edges_e (function ((i1, _), l, (i2, _)) -> fun g ->
- G.add_edge_e g (encode_var n i1 0, 0, encode_var n i2 0)
+ DFG.fold_edges_e (function ((i1, instr1), _, (i2, _)) -> fun g ->
+ let end_sv = pipeline_stages instr1 in
+ G.add_edge_e g (encode_var n i1 end_sv, 0, encode_var n i2 0)
)
let add_ctrl_deps n succs constr =
@@ -607,17 +625,24 @@ let negate_graph constr =
DFG.add_edge_e g (v1, -e, v2)
) constr DFG.empty
-let add_cycle_constr max n dfg constr =
+let add_cycle_constr maxf n dfg constr =
let negated_dfg = negate_graph dfg in
+ let max_initial_del = DFG.fold_vertex (fun v1 g ->
+ if DFG.in_degree dfg v1 = 0
+ then max g (comb_delay (snd v1))
+ else g) dfg 0 in
let longest_path v = BFDFG.all_shortest_paths negated_dfg v
- |> BFDFG.H.to_seq |> List.of_seq in
- let constrained_paths = List.filter (function (v, m) -> - m > max) in
+ |> BFDFG.H.to_seq |> List.of_seq
+ |> List.map (function (x, y) -> (x, y - max_initial_del)) in
+ let constrained_paths = List.filter (function (_, m) -> - m > maxf) in
List.fold_left (fun g -> function (v, v', w) ->
G.add_edge_e g (encode_var n (fst v) 0,
- - (int_of_float (Float.ceil (Float.div (float_of_int w) (float_of_int max))) - 1),
+ - (int_of_float (Float.ceil (Float.div (float_of_int w) (float_of_int maxf))) - 1),
encode_var n (fst v') 0)
) constr (DFG.fold_vertex (fun v l ->
- List.append l (longest_path v |> constrained_paths
+ List.append l (longest_path v (*|> (function l -> List.iter (function (a, x) ->
+ printf "c: %d %d\n" (fst a) x) l; l)*) |> constrained_paths (* |> (function l -> List.iter (function (a, x) ->
+ printf "%d %d\n" (fst a) x) l; l)*)
|> List.map (function (v', w) -> (v, v', - w)))
) dfg [])
@@ -671,6 +696,7 @@ let gather_cfg_constraints c constr curr =
| None -> assert false
| Some { bb_exit = ctrl; _ } ->
add_super_nodes n dfg constr
+ |> add_initial_sv n dfg
|> add_data_deps n dfg
|> add_ctrl_deps n (successors_instr ctrl
|> List.map P.to_int
@@ -703,25 +729,32 @@ let print_lp constr =
let update_schedule v = function Some l -> Some (v :: l) | None -> Some [ v ]
-let parse_soln tree s =
+let parse_soln (tree, bbtree) s =
let r = Str.regexp "var\\([0-9]+\\)n\\([0-9]+\\)_0[ ]+\\([0-9]+\\)" in
- if Str.string_match r s 0 then
- IMap.update
- (Str.matched_group 1 s |> int_of_string)
- (update_schedule
- ( Str.matched_group 2 s |> int_of_string,
- Str.matched_group 3 s |> int_of_string ))
- tree
- else tree
+ let bb = Str.regexp "bb\\([0-9]+\\)_\\([0-9]+\\)[ ]+\\([0-9]+\\)" in
+ let upd s = IMap.update
+ (Str.matched_group 1 s |> int_of_string)
+ (update_schedule
+ ( Str.matched_group 2 s |> int_of_string,
+ Str.matched_group 3 s |> int_of_string ))
+ in
+ if Str.string_match r s 0
+ then (upd s tree, bbtree)
+ else
+ (if Str.string_match bb s 0
+ then (tree, upd s bbtree)
+ else (tree, bbtree))
let solve_constraints constr =
- let oc = open_out "lpsolve.txt" in
+ let (fn, oc) = Filename.open_temp_file "vericert_" "_lp_solve" in
fprintf oc "%s\n" (print_lp constr);
close_out oc;
- Str.split (Str.regexp_string "\n") (read_process "lp_solve lpsolve.txt")
- |> drop 3
- |> List.fold_left parse_soln IMap.empty
+ let res = Str.split (Str.regexp_string "\n") (read_process ("lp_solve " ^ fn))
+ |> drop 3
+ |> List.fold_left parse_soln (IMap.empty, IMap.empty)
+ in
+ (*Sys.remove fn;*) res
let subgraph dfg l =
let dfg' = List.fold_left (fun g v -> DFG.add_vertex g v) DFG.empty l in
@@ -763,20 +796,35 @@ let all_dfs dfg =
if check_in el a then a else
(DFGDfs.fold_component (fun v l -> v :: l) [] dfg' el) :: a) [] roots
+let range s e =
+ List.init (e - s) (fun i -> i)
+ |> List.map (fun x -> x + s)
+
(** Should generate the [RTLPar] code based on the input [RTLBlock] description. *)
-let transf_rtlpar c c' (schedule : (int * int) list IMap.t) =
+let transf_rtlpar c c' schedule =
let f i bb : RTLPar.bblock =
match bb with
| { bb_body = []; bb_exit = c } -> { bb_body = []; bb_exit = c }
| { bb_body = bb_body'; bb_exit = ctrl_flow } ->
let dfg = match PTree.get i c' with None -> assert false | Some x -> x in
- let i_sched = IMap.find (P.to_int i) schedule in
+ let bb_st_e =
+ let m = IMap.find (P.to_int i) (snd schedule) in
+ (List.assq 0 m, List.assq 1 m) in
+ let i_sched = IMap.find (P.to_int i) (fst schedule) in
let i_sched_tree =
List.fold_left combine_bb_schedule IMap.empty i_sched
in
let body = IMap.to_seq i_sched_tree |> List.of_seq |> List.map snd
|> List.map (List.map (fun x -> (x, List.nth bb_body' x)))
in
+ let body2 = List.fold_left (fun x b ->
+ match IMap.find_opt b i_sched_tree with
+ | Some i -> i :: x
+ | None -> [] :: x
+ ) [] (range (fst bb_st_e) (snd bb_st_e + 1))
+ |> List.map (List.map (fun x -> (x, List.nth bb_body' x)))
+ |> List.rev
+ in
(*let final_body = List.map (fun x -> subgraph dfg x |> order_instr) body in*)
let final_body2 = List.map (fun x -> subgraph dfg x
|> (fun x ->
@@ -784,7 +832,9 @@ let transf_rtlpar c c' (schedule : (int * int) list IMap.t) =
|> List.map (subgraph x)
|> List.map (fun y ->
TopoDFG.fold (fun i l -> snd i :: l) y []
- |> List.rev))) body
+ |> List.rev))) body2
+ (*|> (fun x -> TopoDFG.fold (fun i l -> snd i :: l) x [])
+ |> List.rev) body2*)
in
{ bb_body = final_body2;
bb_exit = ctrl_flow
diff --git a/src/hls/ValueInt.v b/src/hls/ValueInt.v
index e434abc..06b5630 100644
--- a/src/hls/ValueInt.v
+++ b/src/hls/ValueInt.v
@@ -22,22 +22,31 @@ From compcert Require Import lib.Integers common.Values.
From vericert Require Import Vericertlib.
(* end hide *)
-(** * Value
+(*|
+=====
+Value
+=====
-A [value] is a bitvector with a specific size. We are using the implementation
+A ``value`` is a bitvector with a specific size. We are using the implementation
of the bitvector by mit-plv/bbv, because it has many theorems that we can reuse.
-However, we need to wrap it with an [Inductive] so that we can specify and match
-on the size of the [value]. This is necessary so that we can easily store
-[value]s of different sizes in a list or in a map.
+However, we need to wrap it with an ``Inductive`` so that we can specify and
+match on the size of the ``value``. This is necessary so that we can easily
+store ``value`` of different sizes in a list or in a map.
-Using the default [word], this would not be possible, as the size is part of the type. *)
+Using the default ``word``, this would not be possible, as the size is part of
+the type.
+|*)
Definition value : Type := int.
-(** ** Value conversions
+(*|
+Value conversions
+=================
-Various conversions to different number types such as [N], [Z], [positive] and
-[int], where the last one is a theory of integers of powers of 2 in CompCert. *)
+Various conversions to different number types such as ``N``, ``Z``, ``positive``
+and ``int``, where the last one is a theory of integers of powers of 2 in
+CompCert.
+|*)
Definition valueToNat (v : value) : nat :=
Z.to_nat (Int.unsigned v).
@@ -83,10 +92,12 @@ Definition valToValue (v : Values.val) : option value :=
| _ => None
end.
-(** Convert a [value] to a [bool], so that choices can be made based on the
-result. This is also because comparison operators will give back [value] instead
-of [bool], so if they are in a condition, they will have to be converted before
-they can be used. *)
+(*|
+Convert a ``value`` to a ``bool``, so that choices can be made based on the
+result. This is also because comparison operators will give back ``value``
+instead of ``bool``, so if they are in a condition, they will have to be
+converted before they can be used.
+|*)
Definition valueToBool (v : value) : bool :=
if Z.eqb (uvalueToZ v) 0 then false else true.
@@ -94,7 +105,10 @@ Definition valueToBool (v : value) : bool :=
Definition boolToValue (b : bool) : value :=
natToValue (if b then 1 else 0).
-(** ** Arithmetic operations *)
+(*|
+Arithmetic operations
+---------------------
+|*)
Inductive val_value_lessdef: val -> value -> Prop :=
| val_value_lessdef_int:
diff --git a/src/hls/Verilog.v b/src/hls/Verilog.v
index cee1d60..72140cd 100644
--- a/src/hls/Verilog.v
+++ b/src/hls/Verilog.v
@@ -142,23 +142,28 @@ Definition nonblock_reg (r : reg) (asr : reg_associations) (v : value) :=
Inductive scl_decl : Type := VScalar (sz : nat).
Inductive arr_decl : Type := VArray (sz : nat) (ln : nat).
-(** * Verilog AST
+(*|
+Verilog AST
+===========
The Verilog AST is defined here, which is the target language of the
compilation.
-** Value
+Value
+-----
-The Verilog [value] is a bitvector containg a size and the actual bitvector. In
-this case, the [Word.word] type is used as many theorems about that bitvector
-have already been proven. *)
+The Verilog ``value`` is a bitvector containg a size and the actual
+bitvector. In this case, the ``Word.word`` type is used as many theorems about
+that bitvector have already been proven.
-(** ** Binary Operators
+Binary Operators
+----------------
These are the binary operations that can be represented in Verilog. Ideally,
multiplication and division would be done by custom modules which could al so be
scheduled properly. However, for now every Verilog operator is assumed to take
-one clock cycle. *)
+one clock cycle.
+|*)
Inductive binop : Type :=
| Vadd : binop (** addition (binary [+]) *)
@@ -184,15 +189,21 @@ Inductive binop : Type :=
| Vshl : binop (** shift left ([<<]) *)
| Vshr : binop (** shift right ([>>>]) *)
| Vshru : binop. (** shift right unsigned ([>>]) *)
-(*| Vror : binop (** shift right unsigned ([>>]) *)*)
+(* Vror : binop (** shift right unsigned ([>>]) *)*)
-(** ** Unary Operators *)
+(*|
+Unary Operators
+---------------
+|*)
Inductive unop : Type :=
| Vneg (** negation ([-]) *)
| Vnot. (** not operation [!] *)
-(** ** Expressions *)
+(*|
+Expressions
+-----------
+|*)
Inductive expr : Type :=
| Vlit : value -> expr
@@ -207,7 +218,10 @@ Inductive expr : Type :=
Definition posToExpr (p : positive) : expr :=
Vlit (posToValue p).
-(** ** Statements *)
+(*|
+Statements
+----------
+|*)
Inductive stmnt : Type :=
| Vskip : stmnt
@@ -220,14 +234,17 @@ with stmnt_expr_list : Type :=
| Stmntnil : stmnt_expr_list
| Stmntcons : expr -> stmnt -> stmnt_expr_list -> stmnt_expr_list.
-(** ** Edges
+(*|
+Edges
+-----
These define when an always block should be triggered, for example if the always
block should be triggered synchronously at the clock edge, or asynchronously for
combinational logic.
-[edge] is not part of [stmnt] in this formalisation because is closer to the
-semantics that are used. *)
+``edge`` is not part of ``stmnt`` in this formalisation because is closer to the
+semantics that are used.
+|*)
Inductive edge : Type :=
| Vposedge : reg -> edge
@@ -235,11 +252,15 @@ Inductive edge : Type :=
| Valledge : edge
| Voredge : edge -> edge -> edge.
-(** ** Module Items
+(*|
+Module Items
+------------
-Module items can either be declarations ([Vdecl]) or always blocks ([Valways]).
-The declarations are always register declarations as combinational logic can be
-done using combinational always block instead of continuous assignments. *)
+Module items can either be declarations (``Vdecl``) or always blocks
+(``Valways``). The declarations are always register declarations as
+combinational logic can be done using combinational always block instead of
+continuous assignments.
+|*)
Inductive io : Type :=
| Vinput : io
@@ -256,16 +277,17 @@ Inductive module_item : Type :=
| Valways_ff : edge -> stmnt -> module_item
| Valways_comb : edge -> stmnt -> module_item.
-(** The main module type containing all the important control signals
+(*|
+The main module type containing all the important control signals
-- [mod_start] If set, starts the computations in the module.
-- [mod_reset] If set, reset the state in the module.
-- [mod_clk] The clock that controls the computation in the module.
-- [mod_args] The arguments to the module.
-- [mod_finish] Bit that is set if the result is ready.
-- [mod_return] The return value that was computed.
-- [mod_body] The body of the module, including the state machine.
-*)
+:mod_start: If set, starts the computations in the module.
+:mod_reset: If set, reset the state in the module.
+:mod_clk: The clock that controls the computation in the module.
+:mod_args: The arguments to the module.
+:mod_finish: Bit that is set if the result is ready.
+:mod_return: The return value that was computed.
+:mod_body: The body of the module, including the state machine.
+|*)
Record module : Type := mkmodule {
mod_start : reg;
@@ -273,7 +295,8 @@ Record module : Type := mkmodule {
mod_clk : reg;
mod_finish : reg;
mod_return : reg;
- mod_st : reg; (**r Variable that defines the current state, it should be internal. *)
+ mod_st : reg; (**r Variable that defines the current state,
+ it should be internal. *)
mod_stk : reg;
mod_stk_len : nat;
mod_args : list reg;
@@ -285,34 +308,39 @@ Definition fundef := AST.fundef module.
Definition program := AST.program fundef unit.
-(** Convert a [positive] to an expression directly, setting it to the right
- size. *)
+(*|
+Convert a ``positive`` to an expression directly, setting it to the right size.
+|*)
+
Definition posToLit (p : positive) : expr :=
Vlit (posToValue p).
Definition fext := unit.
Definition fextclk := nat -> fext.
-(** ** State
+(*|
+State
+-----
+
+The ``state`` contains the following items:
-The [state] contains the following items:
-n
-- Current [module] that is being worked on, so that the state variable can be
-retrieved and set appropriately.
-- Current [module_item] which is being worked on.
-- A contiunation ([cont]) which defines what to do next. The option is to
- either evaluate another module item or go to the next clock cycle. Finally
- it could also end if the finish flag of the module goes high.
+- Current ``module`` that is being worked on, so that the state variable can be
+ retrieved and set appropriately.
+- Current ``module_item`` which is being worked on.
+- A contiunation (``cont``) which defines what to do next. The option is to
+ either evaluate another module item or go to the next clock cycle. Finally it
+ could also end if the finish flag of the module goes high.
- Association list containing the blocking assignments made, or assignments made
in previous clock cycles.
- Nonblocking association list containing all the nonblocking assignments made
in the current module.
- The environment containing values for the input.
-- The program counter which determines the value for the state in this version of
- Verilog, as the Verilog was generated by the RTL, which means that we have to
- make an assumption about how it looks. In this case, that it contains state
- which determines which part of the Verilog is executed. This is then the part
- of the Verilog that should match with the RTL. *)
+- The program counter which determines the value for the state in this version
+ of Verilog, as the Verilog was generated by the RTL, which means that we have
+ to make an assumption about how it looks. In this case, that it contains
+ state which determines which part of the Verilog is executed. This is then
+ the part of the Verilog that should match with the RTL.
+|*)
Inductive stackframe : Type :=
Stackframe :
@@ -432,7 +460,9 @@ Definition handle_def {A : Type} (a : A) (val : option A)
Local Open Scope error_monad_scope.
-(** Return the location of the lhs of an assignment. *)
+(*|
+Return the location of the lhs of an assignment.
+|*)
Inductive location : Type :=
| LocReg (_ : reg)
diff --git a/src/hls/Veriloggen.v b/src/hls/Veriloggen.v
index aba2293..c07e18d 100644
--- a/src/hls/Veriloggen.v
+++ b/src/hls/Veriloggen.v
@@ -25,6 +25,7 @@ Require Import vericert.hls.AssocMap.
Require Import vericert.hls.HTL.
Require Import vericert.hls.ValueInt.
Require Import vericert.hls.Verilog.
+Require Import vericert.hls.FunctionalUnits.
Definition transl_list_fun (a : node * Verilog.stmnt) :=
let (n, stmnt) := a in
@@ -56,9 +57,8 @@ Definition inst_ram clk ram :=
Definition transl_module (m : HTL.module) : Verilog.module :=
let case_el_ctrl := list_to_stmnt (transl_list (PTree.elements m.(mod_controllogic))) in
let case_el_data := list_to_stmnt (transl_list (PTree.elements m.(mod_datapath))) in
- match m.(HTL.mod_ram) with
- | Some ram =>
- let body :=
+ let ram := m.(HTL.mod_ram) in
+ let body :=
Valways (Vposedge m.(HTL.mod_clk)) (Vcond (Vbinop Veq (Vvar m.(HTL.mod_reset)) (Vlit (ZToValue 1)))
(Vnonblock (Vvar m.(HTL.mod_st)) (Vlit (posToValue m.(HTL.mod_entrypoint))))
(Vcase (Vvar m.(HTL.mod_st)) case_el_ctrl (Some Vskip)))
@@ -72,31 +72,11 @@ Definition transl_module (m : HTL.module) : Verilog.module :=
m.(HTL.mod_finish)
m.(HTL.mod_return)
m.(HTL.mod_st)
- m.(HTL.mod_stk)
- m.(HTL.mod_stk_len)
+ m.(HTL.mod_ram).(ram_mem)
+ m.(HTL.mod_ram).(ram_size)
m.(HTL.mod_params)
body
- m.(HTL.mod_entrypoint)
- | None =>
- let body :=
- Valways (Vposedge m.(HTL.mod_clk)) (Vcond (Vbinop Veq (Vvar m.(HTL.mod_reset)) (Vlit (ZToValue 1)))
- (Vnonblock (Vvar m.(HTL.mod_st)) (Vlit (posToValue m.(HTL.mod_entrypoint))))
- (Vcase (Vvar m.(HTL.mod_st)) case_el_ctrl (Some Vskip)))
- :: Valways (Vposedge m.(HTL.mod_clk)) (Vcase (Vvar m.(HTL.mod_st)) case_el_data (Some Vskip))
- :: List.map Vdeclaration (arr_to_Vdeclarr (AssocMap.elements m.(mod_arrdecls))
- ++ scl_to_Vdecl (AssocMap.elements m.(mod_scldecls))) in
- Verilog.mkmodule m.(HTL.mod_start)
- m.(HTL.mod_reset)
- m.(HTL.mod_clk)
- m.(HTL.mod_finish)
- m.(HTL.mod_return)
- m.(HTL.mod_st)
- m.(HTL.mod_stk)
- m.(HTL.mod_stk_len)
- m.(HTL.mod_params)
- body
- m.(HTL.mod_entrypoint)
- end.
+ m.(HTL.mod_entrypoint).
Definition transl_fundef := transf_fundef transl_module.
diff --git a/src/hls/Veriloggenproof.v b/src/hls/Veriloggenproof.v
index d1494ec..90cf4cb 100644
--- a/src/hls/Veriloggenproof.v
+++ b/src/hls/Veriloggenproof.v
@@ -241,7 +241,7 @@ Proof. unfold transl_module; intros; destruct (HTL.mod_ram m) eqn:?; crush. Qed.
Lemma mod_st_equiv m : mod_st (transl_module m) = HTL.mod_st m.
Proof. unfold transl_module; intros; destruct (HTL.mod_ram m) eqn:?; crush. Qed.
-Lemma mod_stk_equiv m : mod_stk (transl_module m) = HTL.mod_stk m.
+(*Lemma mod_stk_equiv m : mod_stk (transl_module m) = HTL.mod_stk m.
Proof. unfold transl_module; intros; destruct (HTL.mod_ram m) eqn:?; crush. Qed.
Lemma mod_stk_len_equiv m : mod_stk_len (transl_module m) = HTL.mod_stk_len m.
@@ -335,7 +335,7 @@ Proof.
Qed.
-Section CORRECTNESS.
+*)Section CORRECTNESS.
Variable prog: HTL.program.
Variable tprog: program.
@@ -345,7 +345,7 @@ Section CORRECTNESS.
Let ge : HTL.genv := Globalenvs.Genv.globalenv prog.
Let tge : genv := Globalenvs.Genv.globalenv tprog.
- Lemma symbols_preserved:
+(* Lemma symbols_preserved:
forall (s: AST.ident), Genv.find_symbol tge s = Genv.find_symbol ge s.
Proof. intros. eapply (Genv.find_symbol_match TRANSL). Qed.
#[local] Hint Resolve symbols_preserved : verilogproof.
@@ -532,13 +532,13 @@ Section CORRECTNESS.
Proof.
intros. inv H0. inv H. inv H3. constructor. reflexivity.
Qed.
- #[local] Hint Resolve transl_final_states : verilogproof.
+ #[local] Hint Resolve transl_final_states : verilogproof.*)
Theorem transf_program_correct:
forward_simulation (HTL.semantics prog) (Verilog.semantics tprog).
Proof.
eapply Smallstep.forward_simulation_plus; eauto with verilogproof.
- apply senv_preserved.
- Qed.
+ (*apply senv_preserved.
+ Qed.*) Admitted.
End CORRECTNESS.