prjunnamed_generic/
lower_arith.rs1use prjunnamed_netlist::{Design, Cell, Value, Net};
2
3fn add_horiz_or(design: &Design, value: Value) -> Net {
4 let mut nets = Vec::from_iter(value.iter());
5 while nets.len() > 1 {
6 for chunk in std::mem::take(&mut nets).chunks(2) {
7 if chunk.len() == 2 {
8 nets.push(design.add_or1(chunk[0], chunk[1]))
9 } else {
10 nets.push(chunk[0]);
11 }
12 }
13 }
14 *nets.first().unwrap_or(&Net::ZERO)
15}
16
17fn lower_shift(
18 design: &Design,
19 value: &Value,
20 amount: &Value,
21 stride: u32,
22 shift: impl Fn(&Value, usize) -> Value,
23 overflow: Value,
24) -> Cell {
25 let mut stride = stride as usize;
26 let mut value = value.clone();
27 for (index, bit) in amount.iter().enumerate() {
28 if stride < value.len() {
29 let shifted = shift(&value, stride);
30 value = design.add_mux(bit, shifted, value);
31 stride *= 2;
32 } else {
33 let did_overflow = add_horiz_or(design, amount.slice(index + 1..));
34 value = design.add_mux(did_overflow, overflow, value);
35 break;
36 }
37 }
38 Cell::Buf(value)
39}
40
41pub fn lower_arith(design: &mut Design) {
42 for cell_ref in design.iter_cells() {
43 let _guard = design.use_metadata_from(&[cell_ref]);
44 let new_cell = match &*cell_ref.get() {
45 Cell::Eq(a, b) => {
46 if a.is_empty() {
47 Cell::Buf(Value::ones(1))
48 } else {
49 let xor = design.add_xor(a, b);
50 Cell::Not(add_horiz_or(design, xor).into())
51 }
52 }
53 Cell::ULt(a, b) => {
54 let b_inv = design.add_not(b);
55 let sub = design.add_adc(a, b_inv, Net::ONE);
56 Cell::Not(sub.msb().into())
57 }
58 Cell::SLt(a, b) => {
59 let a_inv = a.slice(..a.len() - 1).concat(design.add_not(a.msb()));
60 let b_inv = design.add_not(b.slice(..b.len() - 1)).concat(b.msb());
61 let sub = design.add_adc(a_inv, b_inv, Net::ONE);
62 Cell::Not(sub.msb().into())
63 }
64 Cell::Shl(a, b, stride) => {
65 let shift = |value: &Value, amount| Value::zero(amount).concat(value.slice(..value.len() - amount));
66 lower_shift(design, a, b, *stride, shift, Value::zero(a.len()))
67 }
68 Cell::UShr(a, b, stride) => {
69 let shift = |value: &Value, amount| value.slice(amount..).zext(a.len());
70 lower_shift(design, a, b, *stride, shift, Value::zero(a.len()))
71 }
72 Cell::SShr(a, b, stride) => {
73 let shift = |value: &Value, amount| value.slice(amount..).sext(a.len());
74 lower_shift(design, a, b, *stride, shift, Value::from(a.msb()).sext(a.len()))
75 }
76 Cell::XShr(a, b, stride) => {
77 let shift = |value: &Value, amount| value.slice(amount..).concat(Value::undef(amount));
78 lower_shift(design, a, b, *stride, shift, Value::undef(a.len()))
79 }
80 Cell::Mul(a, b) => {
81 let mut value = Value::zero(a.len());
82 for (index, bit) in b.iter().enumerate() {
83 value = design.add_adc(
84 value,
85 Value::zero(index).concat(design.add_mux(bit, a, Value::zero(a.len()))),
86 Net::ZERO,
87 );
88 }
89 Cell::Buf(value.slice(..a.len()))
90 }
91 Cell::UDiv(..)
92 | Cell::UMod(..)
93 | Cell::SDivTrunc(..)
94 | Cell::SModTrunc(..)
95 | Cell::SDivFloor(..)
96 | Cell::SModFloor(..) => {
97 todo!()
98 }
99 _ => continue,
100 };
101 if cfg!(feature = "trace") {
102 eprintln!(">lower {}", design.display_cell(cell_ref));
103 }
104 cell_ref.replace(new_cell);
105 }
106 design.compact();
107}