Source file circuit_bus_map.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
274
275
276
277
open Base
module Bit = Netlist.Bit
module Bus = Netlist.Bus
module Bus_names = Netlist.Bus_names
module Cell = Netlist.Cell
module Port = Netlist.Port
module Select = struct
type t =
{ signal : Hardcaml.Signal.t
; high : int
; low : int
}
[@@deriving sexp_of]
let concat_top_bit t ~top =
match t with
| [] -> [ top ]
| h :: t ->
if Hardcaml.Signal.Uid.equal
(Hardcaml.Signal.uid h.signal)
(Hardcaml.Signal.uid top.signal)
&& top.low = h.high + 1
then { h with high = top.low } :: t
else top :: h :: t
;;
let vdd = { signal = Hardcaml.Signal.vdd; high = 0; low = 0 }
let gnd = { signal = Hardcaml.Signal.gnd; high = 0; low = 0 }
let to_signal selects =
try
let selects =
List.map selects ~f:(fun select ->
Hardcaml.Signal.select select.signal select.high select.low)
in
Ok (Hardcaml.Signal.concat_msb selects)
with
| e ->
Or_error.error_s
[%message "Unable to form signal from selects" (selects : t list) (e : exn)]
;;
end
module Module_input = struct
type t =
{ input_signal : Hardcaml.Signal.t
; bus : Bus.t
}
[@@deriving sexp_of]
end
module Module_inputs = struct
type t = Module_input.t Port.t list
let circuit_input_map (circuit_inputs : Hardcaml.Signal.t Port.t list) =
List.fold
circuit_inputs
~init:(Ok (Map.empty (module String)))
~f:(fun map input ->
let%bind.Or_error map = map in
match Map.add map ~key:input.name ~data:input.value with
| `Ok map -> Ok map
| `Duplicate ->
Or_error.error_s
[%message
"Duplicate circuit inputs provided"
(circuit_inputs : Hardcaml.Signal.t Port.t list)])
;;
let module_input_ports
(circuit_input_map : Hardcaml.Signal.t Map.M(String).t)
(module_ports : Bus.t Port.t list)
=
List.map module_ports ~f:(fun port ->
match Map.find circuit_input_map port.name with
| Some input_signal ->
Ok { port with value = { Module_input.input_signal; bus = port.value } }
| None ->
Or_error.error_s
[%message
"Unable to associate module port with supplied inputs"
(port : Bus.t Port.t)
(circuit_input_map : Hardcaml.Signal.t Map.M(String).t)])
|> Or_error.all
;;
let create
(circuit_inputs : Hardcaml.Signal.t Port.t list)
(module_ports : Bus.t Port.t list)
: t Or_error.t
=
let%bind.Or_error circuit_input_map = circuit_input_map circuit_inputs in
module_input_ports circuit_input_map module_ports
;;
end
module Cell_port = struct
module T = struct
type t =
{ cell_instance_name : string
; port_name : string
}
[@@deriving sexp_of, compare]
end
include T
include Comparator.Make (T)
end
type t =
{ bit_to_select : Select.t Map.M(Int).t
; cell_port_to_wire : Hardcaml.Signal.t Map.M(Cell_port).t
; bus_names : Bus_names.t
}
let add_bus_to_select_map map signal (port : Bus.t Port.t) =
let rec f bit_index map (bits : Bus.t) =
match bits with
| [] -> Ok map
| bit :: bits ->
(match bit with
| Vdd | Gnd | X ->
Or_error.error_s
[%message
"Gnd, Vdd and X are not valid driver signals"
(port : Bus.t Port.t)
(signal : Hardcaml.Signal.t)]
| Index index ->
(match
Map.add
map
~key:index
~data:Select.{ signal; high = bit_index; low = bit_index }
with
| `Ok map -> f (bit_index + 1) map bits
| `Duplicate ->
Or_error.error_s [%message "Driver bit already defined" (index : int)]))
in
f 0 map port.value
;;
let apply_names t signal bus =
if List.is_empty (Hardcaml.Signal.names signal)
then (
let names = Bus_names.find t.bus_names bus in
List.fold names ~init:signal ~f:Hardcaml.Signal.( -- ))
else signal
;;
let add_module_input t input_signal (port : Bus.t Port.t) =
let input_signal = apply_names t (Hardcaml.Signal.wireof input_signal) port.value in
let%bind.Or_error bit_to_select =
add_bus_to_select_map t.bit_to_select input_signal port
in
Ok { t with bit_to_select }
;;
let add_cell_port map signal (cell : Cell.t) (port : _ Port.t) =
match
Map.add
map
~key:Cell_port.{ cell_instance_name = cell.instance_name; port_name = port.name }
~data:signal
with
| `Ok map -> Ok map
| `Duplicate ->
Or_error.error_s
[%message "Cell output port is duplicated" (port : Bus.t Port.t) (cell : Cell.t)]
;;
let add_cell_output t (cell : Cell.t) (port : Bus.t Port.t) =
match port.value with
| [] -> Ok t
| _ ->
let cell_output_signal =
apply_names t (Hardcaml.Signal.wire (List.length port.value)) port.value
in
let%bind.Or_error bit_to_select =
add_bus_to_select_map t.bit_to_select cell_output_signal port
in
let%bind.Or_error cell_port_to_wire =
add_cell_port t.cell_port_to_wire cell_output_signal cell port
in
Ok { t with bit_to_select; cell_port_to_wire }
;;
let find_and_concat_bus_bit map selects (bit : Bit.t) =
let%bind.Or_error selects = selects in
match bit with
| Vdd -> Ok (Select.vdd :: selects)
| Gnd -> Ok (Select.gnd :: selects)
| X -> Ok (Select.gnd :: selects)
| Index i ->
(match Map.find map i with
| None -> Or_error.error_s [%message "Failed to find net in bus map" (i : int)]
| Some select -> Ok (Select.concat_top_bit selects ~top:select))
;;
let signal_of_bus t (bus : Bus.t Port.t) =
let%bind.Or_error selects =
List.fold bus.value ~init:(Ok []) ~f:(fun bus ->
find_and_concat_bus_bit t.bit_to_select bus)
in
let%bind.Or_error signal = Select.to_signal selects in
Ok { Port.name = bus.name; value = apply_names t signal bus.value }
;;
let signal_of_bus_if_not_empty t (bus : Bus.t Port.t) =
if List.is_empty bus.value then None else Some (signal_of_bus t bus)
;;
let wire_of_cell_output t (cell : Cell.t) (port : Bus.t Port.t) =
match port.value with
| [] -> None
| _ ->
(match
Map.find
t.cell_port_to_wire
Cell_port.{ cell_instance_name = cell.instance_name; port_name = port.name }
with
| Some signal -> Some (Ok { Port.name = port.name; value = signal })
| None ->
Some
(Or_error.error_s
[%message
"failed to find cell output port" (port : Bus.t Port.t) (cell : Cell.t)]))
;;
let empty bus_names =
{ bit_to_select = Map.empty (module Int)
; cell_port_to_wire = Map.empty (module Cell_port)
; bus_names
}
;;
let create (module_ : Netlist.Module.t) ~circuit_inputs =
let%bind.Or_error inputs = Module_inputs.create circuit_inputs module_.inputs in
let bus_map = empty module_.bus_names in
match
List.fold inputs ~init:(Ok bus_map) ~f:(fun map port ->
let%bind.Or_error map = map in
add_module_input map port.value.input_signal { port with value = port.value.bus })
with
| Error e -> Or_error.error_s [%message "adding module inputs" (e : Error.t)]
| Ok bus_map ->
(match
List.fold module_.cells ~init:(Ok bus_map) ~f:(fun map cell ->
List.fold cell.outputs ~init:map ~f:(fun map output ->
let%bind.Or_error map = map in
add_cell_output map cell output))
with
| Error e -> Or_error.error_s [%message "adding cell outputs" (e : Error.t)]
| Ok bus_map -> Ok bus_map)
;;