Source file synthesize.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
open Base
open Stdio
module V = Verilog_design
module M = V.Module
let default_passes =
Pass.
[ Proc
; Flatten
; Memory { nomap = true }
; Opt { mux_undef = false }
; Clean
; Opt { mux_undef = true }
; Clean
]
;;
let get_parameters top =
match M.parameters top with
| [] -> None
| params ->
List.map params ~f:(fun p ->
let name = Verilog_design.Parameter.name p in
let value = Verilog_design.Parameter.string_of_value p in
[%string {|-set %{name} %{value}|}])
|> String.concat ~sep:" "
|> Option.some
;;
let get_defines top =
V.defines top
|> List.map ~f:(fun d ->
let value = V.Define.value d in
if V.Define_value.equal No_arg value
then [%string {|-D%{V.Define.name d}|}]
else [%string {|-D%{V.Define.name d}=%{V.Define_value.to_string value}|}])
|> String.concat ~sep:" "
;;
let get_unique_files top predicate =
let rec unique seen modules =
match modules with
| [] -> []
| hd :: tl ->
if Set.mem seen (M.path hd)
then unique seen tl
else hd :: unique (Set.add seen (M.path hd)) tl
in
M.flat_map top ~f:(fun m -> if predicate m then Some m else None)
|> List.filter_opt
|> unique (Set.empty (module String))
|> List.rev
;;
let yosys_script ?(passes = default_passes) verilog_design ~json_file =
let buffer = Buffer.create 1024 in
let add line = Buffer.add_string buffer (line ^ "\n") in
let top = V.top verilog_design in
let params = get_parameters top in
let defines = get_defines verilog_design in
List.iter (get_unique_files top M.blackbox) ~f:(fun m ->
add [%string {|read_verilog %{defines} -defer -lib %{M.path m}|}]);
List.iter
(get_unique_files top (Fn.non M.blackbox))
~f:(fun m -> add [%string {|read_verilog %{defines} -defer %{M.path m}|}]);
Option.iter params ~f:(fun params ->
add [%string "chparam %{params} %{M.module_name top}"]);
add [%string {|hierarchy -top %{M.module_name top}|}];
List.iter passes ~f:(fun pass -> add (Pass.to_string pass));
add [%string {|write_json %{json_file}|}];
Buffer.contents buffer
;;
let tmp_file ~unlink ext =
let name = Filename_unix.temp_file "hardcaml_of_verilog_synthesize_" ext in
if unlink then Stdlib.at_exit (fun () -> Unix.unlink name);
name
;;
let tmp_out_channel ~unlink ext =
let name = tmp_file ~unlink ext in
name, Out_channel.create name
;;
let write_tmp_yosys_script ?passes verilog_design ~json_file =
let script_name, script = tmp_out_channel ~unlink:true ".yosys" in
Out_channel.output_string script (yosys_script ?passes verilog_design ~json_file);
Out_channel.close script;
script_name
;;
let run_yosys ?(verbose = false) args =
let verbose = if verbose then [] else [ "2>/dev/null"; ">/dev/null" ] in
let command =
String.concat ~sep:" " (List.concat [ [ Config.env; Config.yosys ]; args; verbose ])
in
match Unix.system command with
| WEXITED 0 -> Ok ()
| _ -> Or_error.error_s [%message "YOSYS failed."]
;;
let to_json_file ?verbose ?passes verilog_design ~json_file =
let script_name = write_tmp_yosys_script ?passes verilog_design ~json_file in
run_yosys ?verbose [ "-s"; script_name ]
;;
let to_yosys_netlist ?verbose ?passes verilog_design =
let json_file = tmp_file ~unlink:true ".json" in
let%bind.Or_error () = to_json_file ?verbose ?passes verilog_design ~json_file in
let%bind.Or_error json = Or_error.try_with (fun () -> In_channel.read_all json_file) in
Yosys_netlist.of_string json
;;