Source file static.ml
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
(**{1 Static elaboration} *)
(** This step takes a typed program consisting of
- types, functions and constant declarations
- global IO declarations
- typed FSM instances
and produce a representation, consisting of
- the same types, functions and constant declarations
- a elaborated set of FSM instances
In the latter
i) the formal IOs of the corresponding model have been bound to the global IOs;
for ex, if the input program is like
[
fsm model f (in x: bool, out y: int, ...) ... rules | q -> q' when h.(x=1) with y:=0 ...
...
input X: bool
output Y: int
...
fsm f0 = f(X,Y,...)
]
then, the model describing [f0] in the result representation will be like
[
fsm model f (in X: bool, out X: int, ...) ... rules | q -> q' when h.(X=1) with Y:=0 ...
]
Note: the compatibility between formal and actual IOs has already been checked by the typing phase.
ii) the (generic) parameters have been replaced by their actual value
for ex, if the input program is like
[
fsm model f <n: int> (in x: int<n>, ...) ... vars z: int ... rules | q -> q' when h.(x=1).(z<n) ...
...
input X: int<8>
...
fsm f8 = f<8>(X,,...)
]
then, the model describing [f8] in the result representation will be like
[
fsm model f (in X: int<8>, ...) ... vars z: int ... rules | q -> q' when h.(X=1).(z<8) ...
]
Note: the compatibility between formal and actual parameters has already been checked by the typing phase.
iii) Moore-style descriptions (with output assignations attached to states) have been turned to
to Mealy-style ones (with output assignations attached to transitions).
for ex, if the input program is like
[
fsm model f (out o: int, ...) states { ..., q' with o=1 } ... rules | q -> q' ...
...
fsm f0 = f(...)
]
then, the model describing [f0] in the result representation will be like
[
fsm model f (out o: int, ...) states { ..., q } ... rules | q -> q' with o:=1 ...
]
The elaboration step also computes the dependency order induced by shared variables
between FSMs. An FSM [f] depends on another FSM [f'] if [f] reads a variable that is written by [f'].
Note that this order is here purely static because all rules are considered for reading and writing,
independentely of the actual FSM state. The resulting order will used by the SystemC (and possibly other)
backend to implement instantaneous broadcast using delta cycles.
*)
module type T = sig
module Syntax: Syntax.SYNTAX
module Typing: Typing.TYPING with module HostSyntax = Syntax
module Value: Guest.VALUE with type typ = Syntax.typ
(** FSM instances *)
type fsm = {
name: Ident.t;
model: Syntax.model; (** Normalized, type-refined model *)
q: Ident.t;
vars: Value.t Env.t;
}
type ctx_comp = {
ct_typ: Syntax.typ;
ct_stim: Syntax.stimulus_desc option; (** For inputs only *)
ct_rds: Ident.t list; (** Readers, for inputs and shareds *)
ct_wrs: Ident.t list; (** Writers, for outputs and shareds *)
}
type ctx = {
inputs: (Ident.t * ctx_comp) list;
outputs: (Ident.t * ctx_comp) list;
shared: (Ident.t * ctx_comp) list;
}
type t = {
ctx: ctx;
models: Syntax.model list; (** Original, un-type-refined and un-normalized models. Not used any longer *)
fsms: fsm list;
globals: Value.t Env.t; (** Functions and constants *)
fns: Syntax.fun_decl list; (** Functions *)
csts: Syntax.cst_decl list; (** Constants *)
types: Syntax.Guest.type_decl list; (** User-defined types *)
dep_order: (Ident.t * int) list;
}
val build: Typing.typed_program -> Syntax.program -> t
val pp: verbose_level:int -> Format.formatter -> t -> unit
val pp_fsm: verbose_level:int -> Format.formatter -> fsm -> unit
val is_rtl: fsm -> bool
end
module Make
(HS: Syntax.SYNTAX)
(HT: Typing.TYPING with module HostSyntax = HS)
(GV: Guest.VALUE with type typ = HS.typ)
(GS: Guest.STATIC with type expr = HS.expr and type value = GV.t)
: T with module Syntax = HS
and module Typing = HT
and module Value = GV =
struct
module Syntax = HS
module Typing = HT
module Value = GV
type fsm = {
name: Ident.t;
model: Syntax.model;
q: Ident.t;
vars: Value.t Env.t;
}
let pp_fsm ~verbose_level fmt f =
let open Format in
match verbose_level with
| 0 -> Format.fprintf fmt "%a" Ident.pp f.name
| 1 ->
fprintf fmt "@[<h>{@,name=%a,model=%a@,q=%a,@,vars=%a}@]"
Ident.pp f.name
Ident.pp f.model.Annot.desc.name
Ident.pp f.q
(Env.pp Value.pp) f.vars
| _ ->
fprintf fmt "@[<v>{@,name=%a@,model=%a@,q=%a@,vars=%a}@]"
Ident.pp f.name
Syntax.pp_model f.model
Ident.pp f.q
(Env.pp Value.pp) f.vars
type ctx_comp = {
ct_typ: Syntax.typ [@printer fun fmt -> fprintf fmt "%a" (Syntax.Guest.Types.pp_typ ~abbrev:false)];
ct_stim: Syntax.stimulus_desc option;
ct_rds: Ident.t list;
ct_wrs: Ident.t list;
} [@@deriving show {with_path=false}]
type ctx = {
inputs: (Ident.t * ctx_comp) list;
outputs: (Ident.t * ctx_comp) list;
shared: (Ident.t * ctx_comp) list;
}
let pp_ctx fmt ctx =
let open Format in
let pp_io fmt (id,cc) = Format.fprintf fmt "%a: %a" Ident.pp id pp_ctx_comp cc in
fprintf fmt "@[<v>{inputs=%a@,outputs=%a@,shared=%a}@]"
(Ext.List.pp_v pp_io) ctx.inputs
(Ext.List.pp_v pp_io) ctx.outputs
(Ext.List.pp_v pp_io) ctx.shared
type t = {
ctx: ctx;
models: Syntax.model list;
fsms: fsm list;
globals: Value.t Env.t;
fns: Syntax.fun_decl list;
csts: Syntax.cst_decl list;
types: Syntax.Guest.type_decl list;
dep_order: (Ident.t * int) list;
}
let pp ~verbose_level fmt s =
let open Format in
fprintf fmt "@[<v>{ctx=%a@,fsms=%a@,globals=%a@,types=%a@,dep_order=%a@,}@."
pp_ctx s.ctx
(Ext.List.pp_v (pp_fsm ~verbose_level)) s.fsms
(Env.pp Value.pp) s.globals
(Ext.List.pp_v Syntax.pp_type_decl) s.types
(Ext.List.pp_h ~sep:"," (fun fmt (f,d) -> fprintf fmt "%a:%d" Ident.pp f d)) s.dep_order
let r_inst tp senv_i { Annot.desc=name,model,params,args; Annot.loc=loc; _ } =
let open Syntax in
let mm =
try List.assoc name tp.Typing.tp_insts
with Not_found -> Misc.fatal_error "Static.r_inst" in
let m = mm.Annot.desc in
let bind_param (id,_) e = (id, e) in
let phi_p =
try List.map2 bind_param m.params params
with Invalid_argument _ -> Misc.fatal_error "Static.r_inst" in
let bind_arg (l_id,_) g_id = (l_id,g_id) in
let phi_io =
try List.map2 bind_arg m.ios args
with Invalid_argument _ -> Misc.fatal_error "Static.r_inst" in
let erase_params m = { m with Annot.desc = { m.Annot.desc with params = [] } } in
let mm' =
mm
|> normalize_model
|> subst_model_param ~phi:phi_p
|> subst_model_io ~phi:phi_io
|> erase_params in
let collect cats =
List.fold_left2
(fun acc (id,(cat,_)) arg -> if List.mem cat cats then arg::acc else acc)
[]
m.ios
args in
let m' = mm'.Annot.desc in
let rds = collect [Syntax.In; Syntax.InOut] in
let wrs = collect [Syntax.Out; Syntax.InOut] in
let f = {
name = name;
model = mm';
q = fst m'.itrans.Annot.desc;
vars =
List.fold_left
(fun env (id,te) -> Env.add id (Value.default_value te.Annot.typ) env)
Env.empty
m'.vars
} in
f, (name, (rds,wrs))
let r_insts tp senv_i insts = List.map (r_inst tp senv_i) insts
let r_global env { Annot.desc=id,cat,ty,st; _ } =
Env.add id (cat,ty,st) env
let r_globals gls = List.fold_left r_global Env.empty gls
let build_ctx rws senv_i =
let open Syntax in
let type_of te = te.Annot.typ in
let collect_rds i = List.fold_left (fun acc (name,(rds,_)) -> if List.mem i rds then name::acc else acc) [] rws in
let collect_wrs o = List.fold_left (fun acc (name,(_,wrs)) -> if List.mem o wrs then name::acc else acc) [] rws in
let cat acc senv =
Env.fold
(fun id (cat',te,st) acc ->
let t = type_of te in
match cat, cat', st with
| Input, Input, Some { Annot.desc=st'; _ } ->
let cc = { ct_typ=t; ct_stim=Some st'; ct_rds=collect_rds id; ct_wrs=[] } in
(id, cc)::acc
| Output, Output, _ ->
let cc = { ct_typ=t; ct_stim=None; ct_rds=[]; ct_wrs=collect_wrs id } in
(id, cc)::acc
| Shared, Shared, _ ->
let cc = { ct_typ=t; ct_stim=None; ct_rds=collect_rds id; ct_wrs=collect_wrs id } in
(id, cc)::acc
| _, _, _ ->
acc)
senv
[] in
{ inputs = extract Input [] senv_i;
outputs = extract Output [] senv_i;
shared = extract Shared [] senv_i; }
let r_program tp p =
let senv_i = r_globals p.Syntax.globals in
let m, rws = List.split @@ r_insts tp senv_i p.Syntax.insts in
let c = build_ctx rws senv_i in
m, c
let r_const env { Annot.desc = c; _ } =
let open Syntax in
Env.add c.cc_name (GS.eval c.cc_val) env
let r_fun env { Annot.desc = f; _ } =
let open Syntax in
let args = f.ff_args |> List.map fst |> List.map Ident.to_string in
Env.add f.ff_name (GS.eval_fn args f.ff_body) env
let r_globals p =
let env_c = List.fold_left r_const Env.empty p.Syntax.cst_decls in
let env_f = List.fold_left r_fun env_c p.Syntax.fun_decls in
Env.union env_c env_f
module FsmNode =
struct
type t = fsm
type context = ctx
let name_of f = f.name
let depends_on ctx f f' =
List.exists
(fun (v,cc) -> List.mem f.name cc.ct_wrs && List.mem f'.name cc.ct_rds)
ctx.shared
end
let dep_sort ctx fsms =
let module D = Depg.Make(FsmNode) in
D.dep_sort ctx fsms
let build tp p =
let m, c = r_program tp p in
{ ctx = c;
models = p.Syntax.models;
fsms = m;
globals = r_globals p;
fns = p.Syntax.fun_decls;
csts = p.Syntax.cst_decls;
types = p.Syntax.type_decls;
dep_order = m |> dep_sort c |> List.mapi (fun i f -> f.name, i) }
let is_rtl acts =
let module S = Set.Make(Ident) in
let wvars_of_action a =
let open Syntax in
match a.Annot.desc with
| Emit _ -> S.empty
| Assign (lval,_) -> S.of_list (Guest.vars_of_lval lval) in
let rec scan acc acts = match acts with
[] -> true
| a::rest ->
let wvs = wvars_of_action a in
if S.is_empty (S.inter acc wvs)
then scan (S.union acc wvs) rest
else false in
scan S.empty acts
let is_rtl_model { Annot.desc = m; _ } =
let is_rtl_transition { Annot.desc = _,_,acts,_,_; _ } = is_rtl acts in
let is_rtl_itransition { Annot.desc = _,acts; _ } = is_rtl acts in
List.for_all is_rtl_transition m.Syntax.trans
&& is_rtl_itransition m.Syntax.itrans
let is_rtl f = is_rtl_model f.model
end