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
type fsm = {
f_static: Fsm.inst; (** Static representation *)
f_vars: (string * (Types.typ * Expr.value)) list; (** name, (type, value) *)
f_state: string; (** Current state *)
f_has_reacted: bool; (** true when implied in the last reaction *)
}
type lenv = (string * Expr.value) list
type genv = {
fe_inputs: (string * (Types.typ * Expr.value)) list; (** Global inputs *)
fe_csts: (string * (Types.typ * Expr.value)) list; (** Global constants *)
fe_fns: (string * (Types.typ * Expr.value)) list; (** Global functions *)
fe_vars: (string * (Types.typ * Expr.value)) list; (** Shared variables *)
fe_evs: (string * (Types.typ * Expr.value)) list; (** Shared events *)
}
type event = loc * Expr.value (** Event location, new value *)
and loc =
| LVar of Ident.t (** Scalar *)
| LArrInd of Ident.t * int (** 1D array location *)
| LRField of Ident.t * string (** Record field *)
exception IllegalTrans of fsm * string
exception Undeterminate of fsm * string * Types.date
exception NonDetTrans of fsm * Fsm.transition list * Types.date
exception NonAtomicIoWrite of fsm * Action.t
let mk_ival ty = match ty with
| Types.TyArray(TiConst sz, ty') ->
Expr.mk_array (Utils.ListExt.range (function i -> Expr.mk_val ty' Expr.Val_unknown) 1 sz)
| Types.TyArray(_, _) -> Misc.fatal_error "Fsm.Dynamic.mk_ival"
| Types.TyRecord (n,fs) ->
Expr.mk_record n (List.map (function (n,ty) -> n, ty, Expr.mk_val ty Expr.Val_unknown) fs)
| _ -> Expr.mk_val ty Expr.Val_unknown
let mk_var (v,ty) = (v,(ty, mk_ival ty))
let make_fsm sf = {
f_static = sf;
f_vars = List.map mk_var sf.Fsm.f_vars;
f_state = "";
f_has_reacted = false
}
let replace_assoc' k v env =
let rec repl = function
[] -> []
| (k',(x,v'))::rest -> if k=k' then (k,(x,v)) :: repl rest else (k',(x,v')) :: repl rest in
repl env
exception IllegalAction of fsm * Action.t
let do_action (f,resps,resps',env) act =
let open Expr in
let s = f.f_static in
let array_upd id idx v =
match List.assoc id env, Eval.eval env idx with
| { v_desc=Val_array vs} as a, { v_desc=Val_int i } -> { a with v_desc = Val_array (array_update id vs i v) }, i
| _, _ -> raise (IllegalAction (f,act)) in
let record_upd id fd v =
match List.assoc id env with
| { v_desc=Val_record vs } as r -> { r with v_desc = Val_record (record_update id vs fd v) }
| _ -> raise (IllegalAction (f,act)) in
let set_bits id idx1 idx2 v =
match List.assoc id env, Eval.eval env idx1, Eval.eval env idx2, v with
| { v_desc=Val_int x } as u, { v_desc=Val_int hi }, { v_desc=Val_int lo }, { v_desc=Val_int b } ->
{ u with v_desc = Val_int (Intbits.set_bits hi lo x b) }
| _, _, _, _ -> raise (IllegalAction (f,act)) in
match act with
Action.Assign (lhs, expr) ->
let id = Action.lhs_name lhs in
let v = Eval.eval env expr in
if List.mem_assoc id s.f_vars then
begin match Fsm.cfg.act_sem with
| Sequential ->
begin match lhs.l_desc with
| Action.LhsVar id ->
let v' = Eval.eval env expr in
{ f with f_vars = replace_assoc' id v' f.f_vars },
resps @ [LVar (Ident.Local (s.f_name, id)), v'],
resps',
Utils.ListExt.replace_assoc id v' env
| Action.LhsArrInd (id, idx) ->
let v', i = array_upd id idx v in
{ f with f_vars = replace_assoc' id v' f.f_vars },
resps @ [LArrInd (Ident.Local (s.f_name, id), i), v],
resps',
Utils.ListExt.replace_assoc id v' env
| Action.LhsArrRange (id,idx1,idx2) ->
let v' = set_bits id idx1 idx2 v in
{ f with f_vars = replace_assoc' id v' f.f_vars },
resps @ [LVar (Ident.Local (s.f_name, id)), v'],
resps',
Utils.ListExt.replace_assoc id v' env
| Action.LhsRField (id, fd) ->
let v' = record_upd id fd v in
{ f with f_vars = replace_assoc' id v' f.f_vars },
resps @ [LVar (Ident.Local (s.f_name, id)), v'],
resps',
Utils.ListExt.replace_assoc id v' env
end
| Synchronous ->
begin match lhs.l_desc with
| Action.LhsVar id ->
let v' = Eval.eval env expr in
f,
resps,
resps' @ [LVar (Ident.Local (s.f_name, id)), v'],
env
| Action.LhsArrInd (id, idx) ->
let v', i = array_upd id idx v in
f,
resps,
resps' @ [LArrInd (Ident.Local (s.f_name, id), i), v],
env
| Action.LhsArrRange (id, idx1, idx2) ->
let v' = set_bits id idx1 idx2 v in
f,
resps,
resps' @ [LVar (Ident.Local (s.f_name, id)), v'],
env
| Action.LhsRField (id, fd) ->
let v' = record_upd id fd v in
f,
resps,
resps' @ [LRField (Ident.Local (s.f_name, id), fd), v'],
env
end
end
else
begin match lhs.l_desc with
| Action.LhsVar id ->
let v' = Eval.eval env expr in
f,
resps @ [LVar (Ident.Global (s.f_l2g id)), v'],
resps',
env
| Action.LhsArrInd (id, _)
| Action.LhsArrRange (id, _, _)
| Action.LhsRField (id, _) ->
raise (NonAtomicIoWrite (f,act))
end
| Action.Emit id ->
f,
resps @ [LVar (Ident.Global (s.f_l2g id)), Expr.set_event],
resps',
env
| Action.StateMove (id,q,q') ->
{ f with f_state = q' },
resps @ [LVar (Ident.Local (s.f_name, "state")), { v_desc=Val_enum q'; v_typ=TyEnum (Types.new_name_var(),[]) }],
resps',
env
let perform_delayed_action (f,env) (lhs,v) =
let open Expr in
let id, v' = match lhs with
| LVar (Ident.Local (_, id)) -> id, v
| LArrInd (Ident.Local (_, id), i) ->
id,
begin match List.assoc id env with
| { v_desc=Val_array vs } as a -> { a with v_desc = Val_array (array_update id vs i v) }
| _ -> Misc.fatal_error "Fsm_dyn.perform_delayed_action"
end
| _ -> Misc.fatal_error "Fsm_dyn.perform_delayed_action" in
{ f with f_vars = replace_assoc' id v' f.f_vars },
Utils.ListExt.replace_assoc id v' env
let string_of_actions resps =
Utils.ListExt.to_string (function (id,v) -> Ident.to_string id ^ ":=" ^ (Expr.string_of_opt_value v)) "," resps
let do_actions env f acts =
let f', resps', resps'', env' = List.fold_left do_action (f,[],[],env) acts in
match Fsm.cfg.act_sem with
| Sequential ->
f', resps'
| Synchronous ->
let f'', _ = List.fold_left perform_delayed_action (f',env') resps'' in
f'', resps' @ resps''
let mk_local_env f genv =
let s = f.f_static in
let erase_type (id,(ty,v)) = id, v in
let get_value id =
try snd (List.assoc (s.f_l2g id) (genv.fe_inputs @ genv.fe_vars @ genv.fe_evs))
with Not_found -> Misc.fatal_error "Fsm_dyn.mk_local_env" in
List.map (function (id,ty) -> id, get_value id) (s.f_inps @ s.f_inouts)
@ List.map erase_type f.f_vars
@ List.map erase_type (genv.fe_csts @ genv.fe_fns)
let rec react t genv f =
let sf = f.f_static in
let lenv = mk_local_env f genv in
let cross_transition (s,(cond,acts,_,_),s') =
let acts' = if s <> s' then Action.StateMove(sf.f_name,s,s')::acts else acts in
let f', resps' = do_actions lenv f acts' in
{ f' with f_has_reacted=true }, resps' in
let ts = List.filter (fireable f lenv) (Fsm.transitions_of_inst sf) in
match ts with
[] ->
({f with f_has_reacted=false}, [])
| [t1] ->
cross_transition t1
| ts ->
let priority_of (_,(_,_,p,_),_) = p in
let compare_priority t1 t2 = Pervasives.compare (priority_of t2) (priority_of t1) in
begin match List.sort compare_priority ts with
t1::t2::_ ->
if priority_of t1 > priority_of t2 then begin
Printf.printf "Non deterministic transitions found for FSM %s at t=%d: {%s}; chose %s\n"
sf.f_name
t
(Utils.ListExt.to_string Fsm.string_of_transition "," ts)
(Fsm.string_of_transition t1);
cross_transition t1
end
else
raise (NonDetTrans (f,ts,t))
| _ -> Misc.fatal_error "Fsm_dyn.react"
end
and fireable f env (s,(cond,acts,_,_),s') =
f.f_state = s && check_cond f env cond
and check_cond f env (evs,guards) =
List.for_all (is_event_set env) evs && Condition.eval_guards env guards
and is_event_set env e = match List.assoc e env with
{ Expr.v_desc=Val_bool true } -> true
| _ -> false
| exception Not_found -> false
let init genv f =
let sf = f.f_static in
match Fsm.Repr.itransitions sf.f_repr with
| [(([],[]),acts,_,_), s] ->
let env = mk_local_env f genv in
do_actions env f (Action.StateMove (sf.f_name,"",s) :: acts)
| [_] ->
raise (IllegalTrans (f, "illegal initial transition"))
| _ ->
raise (IllegalTrans (f, "muliple initial transitions"))