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
open Base
include Rtl_intf
module Out_channel = Stdio.Out_channel
module Filename = Stdlib.Filename
module Signals_name_map = Rtl_ast.Signals_name_map
module Language = struct
type t =
| Verilog
| Vhdl
[@@deriving sexp_of]
let file_extension = function
| Verilog -> ".v"
| Vhdl -> ".vhd"
;;
end
module Hierarchy_path : sig
type t [@@deriving sexp_of]
val empty : t
val push : t -> string -> t
val is_top_circuit : t -> Circuit.t -> bool
end = struct
type t = string list
let empty = []
let push t s = s :: t
let to_string_list t = List.rev t
let sexp_of_t t = [%sexp (to_string_list t : string list)]
let is_top_circuit t circuit =
match t with
| [ name ] -> String.equal (Circuit.name circuit) name
| _ -> false
;;
end
module Output_mode = struct
type t =
| In_directory of string
| To_buffer of Buffer.t
| To_channel of Out_channel.t
| To_file of string
[@@deriving sexp_of]
end
module Output = struct
module Mode = struct
type t =
| In_directory of string
| To_buffer of Buffer.t
| To_channel of Out_channel.t
| To_file of
{ file : string
; out_channel : Out_channel.t
}
[@@deriving sexp_of]
end
type t =
{ language : Language.t
; mode : Mode.t
}
[@@deriving sexp_of]
let create ~(output_mode : Output_mode.t) ~language =
let mode : Mode.t =
match output_mode with
| In_directory d -> In_directory d
| To_buffer b -> To_buffer b
| To_channel c -> To_channel c
| To_file file -> To_file { file; out_channel = Out_channel.create file }
in
{ language; mode }
;;
module Output_rtl = struct
type t =
{ rtl : Buffer.t
; name_map : Signals_name_map.t
}
let output_new ~blackbox ~(language : Language.t) circuit =
let buffer = Buffer.create 1024 in
match language with
| Verilog ->
let ast =
Rtl_ast.of_circuit ~blackbox (Rtl_name.create (module Rtl_name.Verilog)) circuit
in
Rtl_verilog_of_ast.to_buffer buffer ast;
{ rtl = buffer; name_map = Rtl_ast.Signals_name_map.create ast }
| Vhdl ->
let ast =
Rtl_ast.of_circuit ~blackbox (Rtl_name.create (module Rtl_name.Vhdl)) circuit
in
Rtl_vhdl_of_ast.to_buffer buffer ast;
{ rtl = buffer; name_map = Rtl_ast.Signals_name_map.create ast }
;;
let output_deprecated ~blackbox ~language circuit =
let buffer = Buffer.create 1024 in
let name_map =
match (language : Language.t) with
| Vhdl -> Rtl_deprecated.Vhdl.write blackbox (Buffer.add_string buffer) circuit
| Verilog ->
Rtl_deprecated.Verilog.write blackbox (Buffer.add_string buffer) circuit
in
{ rtl = buffer; name_map }
;;
let use_deprecated_generator = false
let output ~blackbox ~language output circuit =
let rtl =
if use_deprecated_generator
then output_deprecated ~blackbox ~language circuit
else output_new ~blackbox ~language circuit
in
output rtl.rtl;
rtl.name_map
;;
end
let output_circuit (blackbox : bool) t circuit hierarchy_path =
try
let output, close =
match t.mode with
| In_directory directory ->
let name = Circuit.name circuit in
let file_name =
Filename.concat directory (name ^ Language.file_extension t.language)
in
let chan = Out_channel.create file_name in
Out_channel.output_buffer chan, fun () -> Out_channel.close chan
| To_buffer buffer -> Buffer.add_buffer buffer, Fn.id
| To_channel out_channel ->
Out_channel.output_buffer out_channel, Fn.id
| To_file { file = _; out_channel } ->
( Out_channel.output_buffer out_channel
, fun () ->
if Hierarchy_path.is_top_circuit hierarchy_path circuit
then Out_channel.close out_channel )
in
let ret = Output_rtl.output ~blackbox ~language:t.language output circuit in
close ();
ret
with
| exn ->
raise_s
[%message
"Error while writing circuit"
~circuit_name:(Circuit.name circuit : string)
(hierarchy_path : Hierarchy_path.t)
~output:(t : t)
(exn : exn)]
;;
end
module Blackbox = struct
type t =
| None
| Top
| Instantiations
[@@deriving sexp_of]
end
let output_with_name_map
?output_mode
?database
?(blackbox = Blackbox.None)
language
circuit
=
let output_mode =
Option.value
output_mode
~default:
(Output_mode.To_file (Circuit.name circuit ^ Language.file_extension language))
in
let output =
try Output.create ~language ~output_mode with
| exn ->
raise_s
[%message
"Error while initializing output mode."
~circuit_name:(Circuit.name circuit)
(language : Language.t)
(output_mode : Output_mode.t)
(exn : exn)]
in
let database = Option.value database ~default:(Circuit_database.create ()) in
let circuits_already_output = Hash_set.create (module String) in
let name_map = ref (Map.empty (module Signals_name_map.Uid_with_index)) in
let add_to_name_map m =
name_map := Map.merge_skewed !name_map m ~combine:(fun ~key:_ v1 _v2 -> v1)
in
let rec output_circuit blackbox circuit hierarchy_path =
let circuit_name = Circuit.name circuit in
if not (Hash_set.mem circuits_already_output circuit_name)
then (
Hash_set.add circuits_already_output circuit_name;
let hierarchy_path = Hierarchy_path.push hierarchy_path circuit_name in
match (blackbox : Blackbox.t) with
| None ->
output_instantitions (None : Blackbox.t) circuit hierarchy_path;
Output.output_circuit false output circuit hierarchy_path |> add_to_name_map
| Top -> Output.output_circuit true output circuit hierarchy_path |> add_to_name_map
| Instantiations ->
output_instantitions Top circuit hierarchy_path;
Output.output_circuit false output circuit hierarchy_path |> add_to_name_map)
and output_instantitions (blackbox : Blackbox.t) circuit hierarchy_path =
Signal_graph.iter (Circuit.signal_graph circuit) ~f:(fun signal ->
match signal with
| Inst { instantiation; _ } ->
(match Circuit_database.find database ~mangled_name:instantiation.inst_name with
| None ->
()
| Some circuit -> output_circuit blackbox circuit hierarchy_path)
| _ -> ())
in
output_circuit blackbox circuit Hierarchy_path.empty;
!name_map
;;
let output ?output_mode ?database ?blackbox language circuit =
ignore
(output_with_name_map ?output_mode ?database ?blackbox language circuit
: Signals_name_map.t)
;;
let print ?database ?blackbox language circuit =
output ~output_mode:(To_channel Out_channel.stdout) ?database ?blackbox language circuit
;;
module Digest = struct
type t = Md5_lib.t
let create ?database ?blackbox language circuit =
let buffer = Buffer.create 1024 in
output ~output_mode:(To_buffer buffer) ?database ?blackbox language circuit;
Md5_lib.bytes (Buffer.contents_bytes buffer)
;;
let to_string t = Md5_lib.to_hex t
let to_constant t = Constant.of_hex_string ~signedness:Unsigned ~width:128 (to_string t)
let sexp_of_t t = [%sexp_of: string] (to_string t)
let of_verilog verilog = Md5_lib.string verilog
end
module Expert = struct
let output_with_name_map = output_with_name_map
end