prjunnamed_generic/
lower_arith.rs

1use 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}