package rfsm

  1. Overview
  2. Docs
A toolset for describing and simulating StateChart-like state diagrams

Install

Dune Dependency

Authors

Maintainers

Sources

rfsm-v1.6-alpha-3.tbz
sha256=eb9583d2a7e354f00f4e0f6b2ea34f2825c92a15a21b708e03fa72c570104ab6
sha512=baff3194770f85efc55e813bbf5e515e1d0d4fae44c492fc6c15ba4834cc41fae5ecb842de1b1fdea10bafe19b4b72320b829d862aeefc6d58845270d8b3088f

doc/src/rfsm/static.ml.html

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
(**********************************************************************)
(*                                                                    *)
(*              This file is part of the RFSM package                 *)
(*                                                                    *)
(*  Copyright (c) 2018-present, Jocelyn SEROT.  All rights reserved.  *)
(*                                                                    *)
(*  This source code is licensed under the license found in the       *)
(*  LICENSE file in the root directory of this source tree.           *)
(*                                                                    *)
(**********************************************************************)

module DepG =
  Graph.Imperative.Digraph.AbstractLabeled
    (struct type t = string end)  (* Only abstract vertices allow imperative marking .. *)
    (struct
      type t = string
      let compare = Pervasives.compare
      let default = ""
    end)

type t = {
  m_name: string;
  m_models : Fsm.model list;
  m_fsms: Fsm.inst list;
  m_inputs: (string * global) list; 
  m_outputs: (string * global) list; 
  m_types: (string * Types.typ) list; 
  m_fns: (string * global) list; 
  m_consts: (string * global) list; 
  m_shared: (string * global) list; 
  m_deps: dependencies;
  }

and global = Types.typ * mg_desc 
      
and mg_desc =
  | MInp of Global.stim_desc * string list     (** stimuli desc, reader(s) *)
  | MOutp of string list                 (** writer(s) *)
  | MFun of string list * Expr.t         (** args, body *)
  | MConst of Expr.value                 (** value *)
  | MShared of string list * string list (** writer(s), reader(s) *)

and dependencies = {
    md_graph: DepG.t;
    md_node: string -> DepG.V.t;
    }

let extract_globals (inputs,outputs,shared) f =
  let name = f.Fsm.f_name in
  let add_reader (ty,mg) id = match mg with
      MInp (sd, rdrs) -> ty, MInp (sd, id::rdrs)
    | MShared (wrs, rdrs) -> ty, MShared (wrs, id::rdrs)
    | m -> ty, m in
  let add_writer (ty,mg) id = match mg with
      MOutp wrs -> ty, MOutp (id::wrs)
    | MShared (wrs, rdrs) -> ty, MShared (id::wrs, rdrs)
    | m -> ty, m in
  let add_reader_writer (ty,mg) id = match mg with
    | MShared (wrs, rdrs) -> ty, MShared (id::wrs, id::rdrs)
    | m -> ty, m in
  (inputs,outputs,shared)
  |> Misc.fold_left
      (fun (inps,outps,shrds) (_,(_,gl)) -> match gl with
       | Global.GInp (id,ty,sd) ->
          if List.mem_assoc id inps
          then Utils.ListExt.update_assoc add_reader id name inps, outps, shrds
          (* else (id, (ty, MInp (build_stim sd, [name]))) :: inps, outps, shrds *)
          else (id, (ty, MInp (sd, [name]))) :: inps, outps, shrds
       | Global.GShared (id,ty) ->
          if List.mem_assoc id shrds
          then inps, outps, Utils.ListExt.update_assoc add_reader id name shrds
          else inps, outps, (id, (ty, MShared ([], [name]))) :: shrds
       | _ -> inps, outps, shrds)
      f.f_inps
  |> Misc.fold_left
      (fun (inps,outps,shrds) (_,(_,gl)) -> match gl with
       | Global.GOutp (id,ty) ->
          if List.mem_assoc id outps
          then inps, Utils.ListExt.update_assoc add_writer id name outps, shrds
          else inps, (id, (ty, MOutp [name])) :: outps, shrds
       | Global.GShared (id,ty) ->
          if List.mem_assoc id shrds
          then inps, outps, Utils.ListExt.update_assoc add_writer id name shrds
          else inps, outps, (id, (ty, MShared ([name],[]))) :: shrds
       | _ -> inps, outps, shrds)
      f.f_outps
  |> Misc.fold_left
      (fun (inps,outps,shrds) (_,(_,gl)) -> match gl with
       | Global.GShared (id,ty) ->
          if List.mem_assoc id shrds
          then inps, outps, Utils.ListExt.update_assoc add_reader_writer id name shrds
          else inps, outps, (id, (ty, MShared ([name],[]))) :: shrds
       | _ -> inps, outps, shrds)
      f.f_inouts 

let build_dependencies fsms shared =
  let g = DepG.create () in
  let nodes = ref [] in
  let lookup n = try List.assoc n !nodes with Not_found -> Misc.fatal_error "Sysm.build_dependencie.lookup" in
  List.iter
    (function f ->
       let name = f.Fsm.f_name in
       let v = DepG.V.create name in
       nodes := (name, v) :: !nodes;
       DepG.add_vertex g v)
    fsms;
  List.iter   (* Compute dependency graph *)
    (function
       id,(ty,MShared (wrs,rrs)) ->
         List.iter
           (function (s,d) ->
              if s <> d then let e = DepG.E.create (lookup s) id (lookup d) in DepG.add_edge_e g e)
           (* Self-dependencies are deliberately not taken into account *)
           (Utils.ListExt.cart_prod2 wrs rrs)
     | _ -> Misc.fatal_error "Sysm.build_dependencies" (* should not happen *))
  shared;
  let update_dep_depth n =
    match DepG.pred g n with
      [] -> ()
    | preds ->
       let m = List.fold_left (fun z n' -> max z (DepG.Mark.get n')) 0  preds in
       DepG.Mark.set n (m+1) in
  let module T = Graph.Topological.Make(DepG) in
  DepG.Mark.clear g;
  T.iter update_dep_depth g; (* Set dependency depths *)
  { md_graph = g;
    md_node = function n -> try List.assoc n !nodes with Not_found -> Misc.fatal_error "Sysm.build_dependencies.md_node " }

exception Illegal_const_expr of Expr.t

let add_global_type tenv (name,ty) = 
  let open Typing in
  match ty with
  | Types.TyEnum (_, cs) ->
     { tenv with te_defns = (name, ty) :: tenv.te_defns;
                 te_ctors = List.map (function c -> c, ty) cs @ tenv.te_ctors }
  | Types.TyRecord (_, fs) ->
     { tenv with te_defns = (name, ty) :: tenv.te_defns;
                 te_rfields = List.map (function (n,_) -> n, ty) fs @ tenv.te_rfields }
  | _ ->
     { tenv with te_defns = (name, ty) :: tenv.te_defns }

let add_global_value tenv (name, (ty, d)) =
  let open Typing in
  match d with 
  | MConst _
  | MFun _ -> { tenv with te_vars = (name, ty) :: tenv.te_vars }
  | _ -> tenv

let build ~name ?(gtyps=[]) ?(gfns=[]) ?(gcsts=[]) models fsms =
  let tenv =
       Typing.builtin_tenv
    |> Misc.fold_left add_global_type gtyps
    |> Misc.fold_left add_global_value (gcsts @ gfns) in
  let inputs, outputs, shared = List.fold_left extract_globals ([],[],[]) fsms in
  (* Type check FSMs *)
  List.iter (Typing.type_fsm_inst tenv) fsms;
  (* Type check inputs *)
  List.iter (function
    | name, (ty, MInp (sd, _)) -> Typing.type_check_stim tenv name ty sd
    | _, _ -> ())
    inputs;
  { m_name = name;
    m_models = models;
    m_fsms = fsms;
    m_inputs = inputs;
    m_outputs = outputs;
    m_types = gtyps;
    m_fns = gfns;
    m_consts = gcsts;
    m_shared = shared;
    m_deps = build_dependencies fsms shared;
   }

(* DOT output *)

let string_of_global (name, (ty, desc)) =
  let pfx = match desc with
    | MInp _ -> "input"
    | MOutp _ -> "output"
    | MFun _ -> "function"
    | MConst _ -> "const"
    | MShared _ -> "shared" in
  pfx ^ " " ^ name ^ ":" ^ Types.string_of_type ty

let dot_output dir ?(dot_options=[]) ?(fsm_options=[]) m =
  let open Utils in
  let rankdir = if List.mem Utils.Dot.RankdirLR dot_options then "LR" else "UD" in
  let layout, mindist = if List.mem Lascar.Ltsa.Circular dot_options then "circo", 1.5 else "dot", 1.0 in
  let dump_header oc name =
     Printf.fprintf oc "digraph %s {\nlayout = %s;\nrankdir = %s;\nsize = \"8.5,11\";\nlabel = \"\"\n center = 1;\n nodesep = \"0.350000\"\n ranksep = \"0.400000\"\n fontsize = 14;\nmindist=\"%1.1f\"\n" name layout rankdir mindist in
  let fnames = (* Dump all FSM models *)
    List.map
      (Fsm.dot_output_model ~dot_options:dot_options ~options:fsm_options ~dir:dir)
      m.m_models in
  match m.m_fsms with
  | [] -> (* No instance, that's all folks *)
     fnames
  | _ -> (* System, with FSM instances, globals, etc.. *)
     let fname = Filename.concat dir (m.m_name ^ ".dot") in
     let oc = open_out fname in
     dump_header oc m.m_name;
     List.iter
       (Fsm.dot_output_oc oc ~dot_options:(Utils.Dot.SubGraph::dot_options) ~options:(GlobalNames::fsm_options))
       m.m_fsms;
     let caption = StringExt.concat_sep "\\r" 
            [ListExt.to_string string_of_global "\\r" m.m_inputs;
             ListExt.to_string string_of_global "\\r" m.m_outputs;
             ListExt.to_string string_of_global "\\r" m.m_consts;
             ListExt.to_string string_of_global "\\r" m.m_fns;
             ListExt.to_string string_of_global "\\r" m.m_shared] in
     Printf.fprintf oc "%s_globals [label=\"%s\", shape=rect, style=rounded]\n" m.m_name caption;
     Printf.fprintf oc "}\n";
     close_out oc;
     fname :: fnames
  
(* Printing *)

let dump_global oc (name,(ty,g_desc)) =
  let open Utils in
  match g_desc with
  | MInp (sd,rdrs) ->
     Printf.fprintf oc "INPUT %s : %s = %s [-> %s]\n"
       name
       (Types.string_of_type ty)
       (Global.string_of_stim sd)
       (ListExt.to_string Misc.id "," rdrs)
  | MOutp wrs ->
     Printf.fprintf oc "OUTPUT %s : %s [<- %s]\n"
       name
       (Types.string_of_type ty)
       (ListExt.to_string Misc.id "," wrs)
  | MFun (args,body) ->
     Printf.fprintf oc "FUNCTION %s : %s\n"
       name
       (Types.string_of_type ty)
  | MConst v ->
     Printf.fprintf oc "CONST %s : %s\n"
       name
       (Types.string_of_type ty)
  | MShared (wrs,rrs) ->
     Printf.fprintf oc "SHARED %s : %s [<- %s] [-> %s])\n"
       name
       (Types.string_of_type ty)
       (ListExt.to_string Misc.id "," wrs)
       (ListExt.to_string Misc.id "," rrs)

let dump_dependencies m =
  let module G = struct
      include DepG
      let edge_attributes e = [`Label (DepG.E.label e)]
      let default_edge_attributes _ = []
      let vertex_attributes v = [`Label (DepG.V.label v ^ "\\n" ^ (string_of_int (DepG.Mark.get v)))]
      let default_vertex_attributes _ = []
      let vertex_name v = DepG.V.label v
      let graph_attributes _ = []
      let get_subgraph _ = None
    end in
  let module D = Graph.Graphviz.Dot(G) in
  let fname = Filename.concat "." (m.m_name ^ "_deps.dot") in
  let oc = open_out fname in
  D.output_graph oc m.m_deps.md_graph;
  Printf.printf "Wrote file %s\n" fname;  (* Do not add to rfsm.output *)
  close_out oc
  
let dump oc m =
  List.iter (Fsm.dump_inst oc) m.m_fsms;
  List.iter (dump_global oc) m.m_inputs;
  List.iter (dump_global oc) m.m_outputs;
  List.iter (dump_global oc) m.m_fns;
  List.iter (dump_global oc) m.m_shared;
  dump_dependencies m
  
OCaml

Innovation. Community. Security.