lut/
lut.rs

1use bitvec::vec::BitVec;
2use safety_net::{Identifier, Instantiable, Logic, Net, Netlist, Parameter, format_id};
3
4#[derive(Debug, Clone)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6struct Lut {
7    lookup_table: BitVec,
8    id: Identifier,
9    inputs: Vec<Net>,
10    output: Net,
11}
12
13impl Lut {
14    fn new(k: usize, lookup_table: usize) -> Self {
15        let mut bv: BitVec<usize, _> = BitVec::from_element(lookup_table);
16        bv.truncate(1 << k);
17        Lut {
18            lookup_table: bv,
19            id: format_id!("LUT{k}"),
20            inputs: (0..k).map(|i| Net::new_logic(format_id!("I{i}"))).collect(),
21            output: Net::new_logic("O".into()),
22        }
23    }
24
25    fn invert(&mut self) {
26        self.lookup_table = !self.lookup_table.clone();
27    }
28}
29
30impl Instantiable for Lut {
31    fn get_name(&self) -> &Identifier {
32        &self.id
33    }
34
35    fn get_input_ports(&self) -> impl IntoIterator<Item = &Net> {
36        &self.inputs
37    }
38
39    fn get_output_ports(&self) -> impl IntoIterator<Item = &Net> {
40        std::slice::from_ref(&self.output)
41    }
42
43    fn has_parameter(&self, id: &Identifier) -> bool {
44        *id == Identifier::new("INIT".to_string())
45    }
46
47    fn get_parameter(&self, id: &Identifier) -> Option<Parameter> {
48        if self.has_parameter(id) {
49            Some(Parameter::BitVec(self.lookup_table.clone()))
50        } else {
51            None
52        }
53    }
54
55    fn set_parameter(&mut self, id: &Identifier, val: Parameter) -> Option<Parameter> {
56        if !self.has_parameter(id) {
57            return None;
58        }
59
60        let old = Some(Parameter::BitVec(self.lookup_table.clone()));
61
62        if let Parameter::BitVec(bv) = val {
63            self.lookup_table = bv;
64        } else {
65            panic!("Invalid parameter type for INIT");
66        }
67
68        old
69    }
70
71    fn parameters(&self) -> impl Iterator<Item = (Identifier, Parameter)> {
72        std::iter::once((
73            Identifier::new("INIT".to_string()),
74            Parameter::BitVec(self.lookup_table.clone()),
75        ))
76    }
77
78    fn from_constant(val: Logic) -> Option<Self> {
79        match val {
80            Logic::True => Some(Self {
81                lookup_table: BitVec::from_element(1),
82                id: "VDD".into(),
83                inputs: vec![],
84                output: "Y".into(),
85            }),
86            Logic::False => Some(Self {
87                lookup_table: BitVec::from_element(0),
88                id: "GND".into(),
89                inputs: vec![],
90                output: "Y".into(),
91            }),
92            _ => None,
93        }
94    }
95
96    fn get_constant(&self) -> Option<Logic> {
97        match self.id.to_string().as_str() {
98            "VDD" => Some(Logic::True),
99            "GND" => Some(Logic::False),
100            _ => None,
101        }
102    }
103
104    fn is_seq(&self) -> bool {
105        false
106    }
107}
108
109fn main() {
110    let netlist = Netlist::new("example".to_string());
111
112    // Add the the two inputs
113    let a = netlist.insert_input("a".into());
114    let b = netlist.insert_input("b".into());
115
116    // Instantiate an NAND gate
117    let instance = netlist
118        .insert_gate(Lut::new(2, 7), "inst_0".into(), &[a, b])
119        .unwrap();
120
121    // Let's make it an AND gate by inverting the lookup table
122    instance.get_instance_type_mut().unwrap().invert();
123
124    // Make this LUT an output
125    instance.expose_with_name("y".into());
126
127    // Print the netlist
128    println!("{netlist}");
129
130    #[cfg(feature = "serde")]
131    {
132        let res = netlist.reclaim().unwrap().serialize(std::io::stdout());
133        if res.is_err() {
134            eprintln!("Failed to serialize netlist: {:?}", res.err());
135        }
136    }
137}