package hardcaml_of_verilog

  1. Overview
  2. Docs

Source file verilog_design.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
open Base

module Parameter = struct
  type t = Hardcaml.Parameter.t [@@deriving equal]

  type simple_parameter = Hardcaml.Parameter_name.t * Hardcaml.Parameter.Value.t
  [@@deriving sexp]

  let sexp_of_t (t : Hardcaml.Parameter.t) = sexp_of_simple_parameter (t.name, t.value)

  let t_of_sexp s =
    let name, value = simple_parameter_of_sexp s in
    { Hardcaml.Parameter.name; value }
  ;;

  let create = Hardcaml.Parameter.create
  let name { Hardcaml.Parameter.name; value = _ } = Hardcaml.Parameter_name.to_string name
  let value { Hardcaml.Parameter.name = _; value } = value

  let string_of_value { Hardcaml.Parameter.name = _; value } =
    match value with
    | Int i -> Int.to_string i
    | String s -> "\"" ^ s ^ "\""
    | _ ->
      raise_s [%message "Invalid parameter type" (value : Hardcaml.Parameter.Value.t)]
  ;;
end

module Parameters = struct
  type t = Parameter.t list [@@deriving sexp, equal]

  let rec replace (t : t) (parameter : Parameter.t) =
    match t with
    | [] -> []
    | hd :: tl ->
      if Hardcaml.Parameter_name.equal hd.name parameter.name
      then parameter :: tl
      else hd :: replace tl parameter
  ;;

  let replace t ~with_ = List.fold with_ ~init:t ~f:(fun ps p -> replace ps p)
end

module Define_value = struct
  type t =
    | String of string
    | Int of int
    | No_arg
  [@@deriving sexp, equal]

  let to_string = function
    | Int i -> Int.to_string i
    | String s -> (* strings are not quoted in defines *) s
    | No_arg -> raise_s [%message "Cannot convert [Define_value.No_arg] to string"]
  ;;
end

module Define = struct
  type t =
    { name : string
    ; value : Define_value.t
    }
  [@@deriving equal, fields ~getters]

  type simple_define = string * Define_value.t [@@deriving sexp]

  let sexp_of_t (t : t) = sexp_of_simple_define (t.name, t.value)

  let t_of_sexp s =
    let name, value = simple_define_of_sexp s in
    { name; value }
  ;;

  let create ~name ~value = { name; value }
end

module Defines = struct
  type t = Define.t list [@@deriving sexp, equal]
end

module Path = struct
  type t = string [@@deriving sexp, equal]
end

module Module = struct
  type t =
    { module_name : string
    ; path : Path.t
    ; instantiates : t list [@sexp.default []]
    ; parameters : Parameters.t [@sexp.default []]
    ; blackbox : bool [@sexp.default false]
    }
  [@@deriving sexp, fields ~getters]

  let create
    ?(blackbox = false)
    ?(parameters = [])
    ?(instantiates = [])
    ~module_name
    ~path
    ()
    =
    { module_name; path; instantiates; parameters; blackbox }
  ;;

  let override ?module_name ?path ?instantiates ?parameters ?blackbox t =
    let module_name = Option.value module_name ~default:t.module_name in
    let path = Option.value path ~default:t.path in
    let instantiates = Option.value instantiates ~default:t.instantiates in
    let parameters = Option.value parameters ~default:t.parameters in
    let blackbox = Option.value blackbox ~default:t.blackbox in
    create ~module_name ~path ~instantiates ~parameters ~blackbox ()
  ;;

  let rec iter t ~f =
    List.iter (instantiates t) ~f:(fun t -> iter t ~f);
    f t
  ;;

  let rec map t ~f =
    f { t with instantiates = List.map (instantiates t) ~f:(fun t -> map t ~f) }
  ;;

  let rec flat_map t ~f =
    let x = List.map (instantiates t) ~f:(fun t -> flat_map t ~f) |> List.concat in
    f t :: x
  ;;
end

type t =
  { top : Module.t
  ; defines : Defines.t [@sexp.default []]
  }
[@@deriving sexp, fields ~getters]

let create ?(defines = []) ~top () = { top; defines }
let top_name t = t.top.module_name
let override_parameters t parameters = { t with top = Module.override ~parameters t.top }

let map_paths t ~f =
  { t with
    top = Module.map t.top ~f:(fun m -> Module.override ~path:(f (Module.path m)) m)
  }
;;

module type Crunched = sig
  val read : string -> string option
end

let find_in_crunched crunched path =
  List.find_map crunched ~f:(fun (module Crunched : Crunched) -> Crunched.read path)
  |> Option.value_exn
       ~error:
         (Error.create_s [%message "Unable to extract crunched file" (path : string)])
;;

let map_crunched_paths ?(delete_temp_files = true) crunched t =
  let seen = Hashtbl.create (module String) in
  map_paths t ~f:(fun path ->
    match Hashtbl.find seen path with
    | Some path -> path
    | None ->
      let tmp_file = Filename_unix.temp_file "crunched" ".v" in
      if delete_temp_files then Stdlib.at_exit (fun () -> Unix.unlink tmp_file);
      let data = find_in_crunched crunched path in
      Stdio.Out_channel.write_all tmp_file ~data;
      Hashtbl.set seen ~key:path ~data:tmp_file;
      tmp_file)
;;

module type Embedded_files = sig
  val by_filename : (string * string) list
end

let find_in_embedded_files embedded_files path =
  (* embed file strips any leading path out. *)
  let file = Stdlib.Filename.basename path in
  match
    List.find_map embedded_files ~f:(fun (module Embedded_files : Embedded_files) ->
      List.Assoc.find Embedded_files.by_filename file ~equal:String.equal)
  with
  | None -> raise_s [%message "Unable to extract crunched file" (path : string)]
  | Some data -> data
;;

let map_embed_file_paths ?(delete_temp_files = true) embedded_files t =
  let seen = Hashtbl.create (module String) in
  map_paths t ~f:(fun path ->
    match Hashtbl.find seen path with
    | Some path -> path
    | None ->
      let tmp_file = Filename_unix.temp_file "crunched" ".v" in
      if delete_temp_files then Stdlib.at_exit (fun () -> Unix.unlink tmp_file);
      let data = find_in_embedded_files embedded_files path in
      Stdio.Out_channel.write_all tmp_file ~data;
      Hashtbl.set seen ~key:path ~data:tmp_file;
      tmp_file)
;;
OCaml

Innovation. Community. Security.