1use std::collections::BTreeSet;
2
3use prjunnamed_netlist::{Cell, Const, Design, FlipFlop, Net, Value};
4
5pub fn split(design: &mut Design) -> bool {
6 let mut live_nets = BTreeSet::<Net>::new();
7 let mut queue = BTreeSet::<Net>::new();
8
9 for cell_ref in design.iter_cells() {
11 let cell = cell_ref.get();
12 if cell.has_effects(design) {
13 cell.visit(|net| {
14 queue.insert(net);
15 })
16 }
17 }
18
19 while let Some(net) = queue.pop_first() {
21 if live_nets.contains(&net) {
22 continue;
23 }
24 live_nets.insert(net);
25 if let Ok((cell_ref, offset)) = design.find_cell(net) {
26 match &*cell_ref.get() {
27 Cell::Buf(arg) | Cell::Not(arg) => {
28 queue.insert(arg[offset]);
29 }
30 Cell::And(arg1, arg2) | Cell::Or(arg1, arg2) | Cell::Xor(arg1, arg2) => {
31 queue.insert(arg1[offset]);
32 queue.insert(arg2[offset]);
33 }
34 Cell::Mux(arg1, arg2, arg3) => {
35 queue.insert(*arg1);
36 queue.insert(arg2[offset]);
37 queue.insert(arg3[offset]);
38 }
39 Cell::Adc(arg1, arg2, arg3) => {
40 queue.insert(*arg3);
41 for index in 0..(offset + 1).min(arg1.len()) {
42 queue.insert(arg1[index]);
43 queue.insert(arg2[index]);
44 }
45 }
46
47 Cell::Shl(arg1, arg2, _) => {
48 for index in 0..(offset + 1) {
49 queue.insert(arg1[index]);
50 }
51 for net in arg2 {
52 queue.insert(net);
53 }
54 }
55 Cell::UShr(arg1, arg2, _) | Cell::SShr(arg1, arg2, _) | Cell::XShr(arg1, arg2, _) => {
56 for index in offset..(arg1.len()) {
57 queue.insert(arg1[index]);
58 }
59 for net in arg2 {
60 queue.insert(net);
61 }
62 }
63
64 Cell::Mul(arg1, arg2) => {
65 for index in 0..(offset + 1) {
66 queue.insert(arg1[index]);
67 queue.insert(arg2[index]);
68 }
69 }
70
71 Cell::Dff(ff) => {
72 queue.insert(ff.data[offset]);
73 queue.insert(ff.clock.net());
74 queue.insert(ff.reset.net());
75 queue.insert(ff.clear.net());
76 queue.insert(ff.enable.net());
77 }
78
79 Cell::Debug(..) => (),
80
81 cell => cell.visit(|net| {
82 queue.insert(net);
83 }),
84 }
85 }
86 }
87
88 for cell_ref in design.iter_cells() {
90 let _guard = design.use_metadata_from(&[cell_ref]);
91 let cell = cell_ref.get();
92 let cell_output = cell_ref.output();
93 let count_live = cell_output.iter().filter(|net| live_nets.contains(&net)).count();
94 if cell.has_effects(design) {
95 continue; } else if count_live == cell_ref.output_len() {
97 continue; } else if count_live == 0 {
99 continue; }
101 let out_low_dead_count = cell_output.iter().position(|net| live_nets.contains(&net)).unwrap();
103 let out_high_dead_count = cell_output.iter().rev().position(|net| live_nets.contains(&net)).unwrap();
104 let out_live_nets = Value::from_iter(cell_output.iter().filter(|net| live_nets.contains(net)));
105 let arg_live_nets = |arg: &Value| {
106 Value::from_iter(
107 cell_output
108 .iter()
109 .enumerate()
110 .filter(|&(_offset, out_net)| live_nets.contains(&out_net))
111 .map(|(offset, _out_net)| arg[offset]),
112 )
113 };
114 let arg_live_trits = |arg: &Const| {
115 Const::from_iter(
116 cell_output
117 .iter()
118 .enumerate()
119 .filter(|&(_offset, out_net)| live_nets.contains(&out_net))
120 .map(|(offset, _out_net)| arg[offset]),
121 )
122 };
123 let (from_live_nets, to_live_nets) = match &*cell {
124 Cell::Buf(arg) => (out_live_nets, design.add_buf(arg_live_nets(arg))),
125 Cell::Not(arg) => (out_live_nets, design.add_not(arg_live_nets(arg))),
126 Cell::And(arg1, arg2) => (out_live_nets, design.add_and(arg_live_nets(arg1), arg_live_nets(arg2))),
127 Cell::Or(arg1, arg2) => (out_live_nets, design.add_or(arg_live_nets(arg1), arg_live_nets(arg2))),
128 Cell::Xor(arg1, arg2) => (out_live_nets, design.add_xor(arg_live_nets(arg1), arg_live_nets(arg2))),
129 Cell::Mux(arg1, arg2, arg3) => {
130 (out_live_nets, design.add_mux(*arg1, arg_live_nets(arg2), arg_live_nets(arg3)))
131 }
132 Cell::Adc(arg1, arg2, arg3) if out_high_dead_count > 1 => {
133 let new_width = arg1.len() - (out_high_dead_count - 1);
134 (
135 cell_output.slice(..new_width),
136 design.add_adc(arg1.slice(..new_width), arg2.slice(..new_width), *arg3).slice(..new_width),
137 )
138 }
139 Cell::Shl(arg1, arg2, stride) if out_high_dead_count > 0 => {
140 let new_width = arg1.len() - out_high_dead_count;
141 (cell_output.slice(..new_width), design.add_shl(arg1.slice(..new_width), arg2, *stride))
142 }
143 Cell::UShr(arg1, arg2, stride) if out_low_dead_count > 0 => (
144 cell_output.slice(out_low_dead_count..),
145 design.add_ushr(arg1.slice(out_low_dead_count..), arg2, *stride),
146 ),
147 Cell::SShr(arg1, arg2, stride) if out_low_dead_count > 0 => (
148 cell_output.slice(out_low_dead_count..),
149 design.add_sshr(arg1.slice(out_low_dead_count..), arg2, *stride),
150 ),
151 Cell::XShr(arg1, arg2, stride) if out_low_dead_count > 0 => (
152 cell_output.slice(out_low_dead_count..),
153 design.add_xshr(arg1.slice(out_low_dead_count..), arg2, *stride),
154 ),
155 Cell::Mul(arg1, arg2) if out_high_dead_count > 0 => {
156 let new_width = arg1.len() - out_high_dead_count;
157 (cell_output.slice(..new_width), design.add_mul(arg1.slice(..new_width), arg2.slice(..new_width)))
158 }
159 Cell::Dff(flip_flop) => (
160 out_live_nets,
161 design.add_dff(FlipFlop {
162 data: arg_live_nets(&flip_flop.data),
163 clock: flip_flop.clock,
164 clear: flip_flop.clear,
165 reset: flip_flop.reset,
166 enable: flip_flop.enable,
167 reset_over_enable: flip_flop.reset_over_enable,
168 clear_value: arg_live_trits(&flip_flop.clear_value),
169 reset_value: arg_live_trits(&flip_flop.reset_value),
170 init_value: arg_live_trits(&flip_flop.init_value),
171 }),
172 ),
173 _ => continue,
174 };
175 if cfg!(feature = "trace") {
176 eprintln!(">split {} => {}", design.display_value(&from_live_nets), design.display_value(&to_live_nets));
177 }
178 design.replace_value(from_live_nets, to_live_nets);
179 }
180
181 design.compact()
182}