forked from mit-plv/koika
-
Notifications
You must be signed in to change notification settings - Fork 0
/
collatz.v
122 lines (94 loc) · 4.07 KB
/
collatz.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
(*! Computing terms of the Collatz sequence (Coq version) !*)
Require Import Koika.Frontend.
Module Collatz.
(*! We have one register ``r0``: !*)
Inductive reg_t := r0.
(*! …and two rules ``divide`` and ``multiply``: !*)
Inductive rule_name_t := divide | multiply.
Definition logsz := 4.
Notation sz := (pow2 logsz).
(*! ``r0`` is a register storing 2^4 = 16 bits: !*)
Definition R r :=
match r with
| r0 => bits_t sz
end.
(*! ``r0`` is initialized to 18: !*)
Definition r idx : R idx :=
match idx with
| r0 => Bits.of_nat sz 18
end.
Definition times_three : UInternalFunction reg_t empty_ext_fn_t :=
{{ fun times_three (bs: bits_t 16) : bits_t 16 =>
(bs << Ob~1) + bs }}.
(*! Our first rule, ``divide``, reads from r0 and halves the result if it's even: !*)
Definition _divide : uaction reg_t empty_ext_fn_t :=
{{ let v := read0(r0) in
let odd := v[Ob~0~0~0~0] in
if !odd then
write0(r0,v >> Ob~1)
else
fail }}.
(*! Our second rule, ``multiply``, reads the output of ``divide`` and
multiplies it by three and ads one if it is odd: !*)
Definition _multiply : uaction reg_t empty_ext_fn_t :=
{{ let v := read1(r0) in
let odd := v[Ob~0~0~0~0] in
if odd then
write1(r0, times_three(v) + Ob~0~0~0~0~0~0~0~0~0~0~0~0~0~0~0~1)
else
fail }}.
(*! The design's schedule defines the order in which rules should (appear to) run !*)
Definition collatz : scheduler :=
divide |> multiply |> done.
(*! Rules are written in an untyped language, so we need to typecheck them: !*)
Definition rules :=
tc_rules R empty_Sigma
(fun r => match r with
| divide => _divide
| multiply => _multiply
end).
(*! And now we can compute results: uncomment the ``Print`` commands below to show results. !*)
Definition cr := ContextEnv.(create) r.
Definition divide_result :=
tc_compute (interp_action cr empty_sigma CtxEmpty log_empty log_empty
(rules divide)).
(*! The output of ``divide`` when ``r0 = 18``: a write to ``r0`` with value ``0b1001 = 9``: !*)
(* Print divide_result. *)
Definition multiply_result :=
tc_compute
(let '(log, _, _) := must divide_result in
interp_action cr empty_sigma CtxEmpty log_empty log (rules multiply)).
(*! The output of ``multiply`` when ``r0 = 9``: a write to ``r0`` with value ``0b11100 = 28``: !*)
(* Print multiply_result. *)
Definition cycle_log :=
tc_compute (interp_scheduler cr empty_sigma rules collatz).
(*! The complete log over the first cycle: two writes to ``r0`` !*)
(* Print cycle_log. *)
Definition result :=
tc_compute (commit_update cr cycle_log).
(*! The values of the registers after the first cycle completes: ``r0 = 28`` !*)
(* Print result. *)
Definition external (r: rule_name_t) := false.
Definition circuits :=
compile_scheduler rules external collatz.
Definition circuits_result :=
tc_compute (interp_circuits empty_sigma circuits (lower_r (ContextEnv.(create) r))).
(*! The same values computed by running compiled circuits: ``r0 = 28`` !*)
(* Print circuits_result. *)
Example test: circuits_result = Environments.map _ (fun _ => bits_of_value) result :=
eq_refl.
(*! This package configures compilation to C++ with Cuttlesim and Verilog with Kôika's verified compiler: !*)
Definition package :=
{| ip_koika := {| koika_reg_types := R;
koika_reg_init := r;
koika_ext_fn_types := empty_Sigma;
koika_rules := rules;
koika_rule_external := external;
koika_scheduler := collatz;
koika_module_name := "collatz" |};
ip_sim := {| sp_ext_fn_specs := empty_ext_fn_props;
sp_prelude := None |};
ip_verilog := {| vp_ext_fn_specs := empty_ext_fn_props |} |}.
End Collatz.
(*! This is the entry point used by the compiler: !*)
Definition prog := Interop.Backends.register Collatz.package.