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 let (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.load_data[offset]);
74 queue.insert(ff.clock.net());
75 queue.insert(ff.reset.net());
76 queue.insert(ff.load.net());
77 queue.insert(ff.clear.net());
78 queue.insert(ff.enable.net());
79 }
80
81 Cell::Debug(..) => (),
82
83 cell => cell.visit(|net| {
84 queue.insert(net);
85 }),
86 }
87 }
88
89 for cell_ref in design.iter_cells() {
91 let _guard = design.use_metadata_from(&[cell_ref]);
92 let cell = cell_ref.get();
93 let cell_output = cell_ref.output();
94 let count_live = cell_output.iter().filter(|net| live_nets.contains(net)).count();
95 if cell.has_effects(design) {
96 continue; } else if count_live == cell_ref.output_len() {
98 continue; } else if count_live == 0 {
100 continue; }
102 let out_low_dead_count = cell_output.iter().position(|net| live_nets.contains(&net)).unwrap();
104 let out_high_dead_count = cell_output.iter().rev().position(|net| live_nets.contains(&net)).unwrap();
105 let out_live_nets = Value::from_iter(cell_output.iter().filter(|net| live_nets.contains(net)));
106 let arg_live_nets = |arg: &Value| {
107 Value::from_iter(
108 cell_output
109 .iter()
110 .enumerate()
111 .filter(|&(_offset, out_net)| live_nets.contains(&out_net))
112 .map(|(offset, _out_net)| arg[offset]),
113 )
114 };
115 let arg_live_trits = |arg: &Const| {
116 Const::from_iter(
117 cell_output
118 .iter()
119 .enumerate()
120 .filter(|&(_offset, out_net)| live_nets.contains(&out_net))
121 .map(|(offset, _out_net)| arg[offset]),
122 )
123 };
124 let (from_live_nets, to_live_nets) = match &*cell {
125 Cell::Buf(arg) => (out_live_nets, design.add_buf(arg_live_nets(arg))),
126 Cell::Not(arg) => (out_live_nets, design.add_not(arg_live_nets(arg))),
127 Cell::And(arg1, arg2) => (out_live_nets, design.add_and(arg_live_nets(arg1), arg_live_nets(arg2))),
128 Cell::Or(arg1, arg2) => (out_live_nets, design.add_or(arg_live_nets(arg1), arg_live_nets(arg2))),
129 Cell::Xor(arg1, arg2) => (out_live_nets, design.add_xor(arg_live_nets(arg1), arg_live_nets(arg2))),
130 Cell::Mux(arg1, arg2, arg3) => {
131 (out_live_nets, design.add_mux(*arg1, arg_live_nets(arg2), arg_live_nets(arg3)))
132 }
133 Cell::Adc(arg1, arg2, arg3) if out_high_dead_count > 1 => {
134 let new_width = arg1.len() - (out_high_dead_count - 1);
135 (
136 cell_output.slice(..new_width),
137 design.add_adc(arg1.slice(..new_width), arg2.slice(..new_width), *arg3).slice(..new_width),
138 )
139 }
140 Cell::Shl(arg1, arg2, stride) if out_high_dead_count > 0 => {
141 let new_width = arg1.len() - out_high_dead_count;
142 (cell_output.slice(..new_width), design.add_shl(arg1.slice(..new_width), arg2, *stride))
143 }
144 Cell::UShr(arg1, arg2, stride) if out_low_dead_count > 0 => (
145 cell_output.slice(out_low_dead_count..),
146 design.add_ushr(arg1.slice(out_low_dead_count..), arg2, *stride),
147 ),
148 Cell::SShr(arg1, arg2, stride) if out_low_dead_count > 0 => (
149 cell_output.slice(out_low_dead_count..),
150 design.add_sshr(arg1.slice(out_low_dead_count..), arg2, *stride),
151 ),
152 Cell::XShr(arg1, arg2, stride) if out_low_dead_count > 0 => (
153 cell_output.slice(out_low_dead_count..),
154 design.add_xshr(arg1.slice(out_low_dead_count..), arg2, *stride),
155 ),
156 Cell::Mul(arg1, arg2) if out_high_dead_count > 0 => {
157 let new_width = arg1.len() - out_high_dead_count;
158 (cell_output.slice(..new_width), design.add_mul(arg1.slice(..new_width), arg2.slice(..new_width)))
159 }
160 Cell::Dff(flip_flop) => (
161 out_live_nets,
162 design.add_dff(FlipFlop {
163 data: arg_live_nets(&flip_flop.data),
164 clock: flip_flop.clock,
165 clear: flip_flop.clear,
166 load: flip_flop.load,
167 load_data: arg_live_nets(&flip_flop.load_data),
168 reset: flip_flop.reset,
169 enable: flip_flop.enable,
170 reset_over_enable: flip_flop.reset_over_enable,
171 clear_value: arg_live_trits(&flip_flop.clear_value),
172 reset_value: arg_live_trits(&flip_flop.reset_value),
173 init_value: arg_live_trits(&flip_flop.init_value),
174 }),
175 ),
176 _ => continue,
177 };
178 if cfg!(feature = "trace") {
179 eprintln!(">split {} => {}", design.display_value(&from_live_nets), design.display_value(&to_live_nets));
180 }
181 design.replace_value(from_live_nets, to_live_nets);
182 }
183
184 design.compact()
185}