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) -> &[Net] {
36 &self.inputs
37 }
38
39 fn get_output_ports(&self) -> &[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 panic!("Parameter {} not applicable", id);
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 clear_parameter(&mut self, id: &Identifier) -> Option<Parameter> {
72 if self.has_parameter(id) {
73 panic!("LUT truth table cannot be cleared");
74 }
75
76 None
77 }
78
79 fn parameters(&self) -> Vec<(Identifier, Parameter)> {
80 vec![(
81 Identifier::new("INIT".to_string()),
82 Parameter::BitVec(self.lookup_table.clone()),
83 )]
84 }
85
86 fn from_constant(val: Logic) -> Option<Self> {
87 match val {
88 Logic::True => Some(Self {
89 lookup_table: BitVec::from_element(1),
90 id: "VDD".into(),
91 inputs: vec![],
92 output: "Y".into(),
93 }),
94 Logic::False => Some(Self {
95 lookup_table: BitVec::from_element(0),
96 id: "GND".into(),
97 inputs: vec![],
98 output: "Y".into(),
99 }),
100 _ => None,
101 }
102 }
103
104 fn get_constant(&self) -> Option<Logic> {
105 match self.id.to_string().as_str() {
106 "VDD" => Some(Logic::True),
107 "GND" => Some(Logic::False),
108 _ => None,
109 }
110 }
111
112 fn is_seq(&self) -> bool {
113 false
114 }
115}
116
117fn main() {
118 let netlist = Netlist::new("example".into());
119
120 let a = netlist.insert_input("a".into());
122 let b = netlist.insert_input("b".into());
123
124 let instance = netlist
126 .insert_gate(Lut::new(2, 7), "inst_0".into(), &[a, b])
127 .unwrap();
128
129 instance.get_instance_type_mut().unwrap().invert();
131
132 instance.expose_with_name("y".into());
134
135 println!("{netlist}");
137
138 #[cfg(feature = "serde")]
139 {
140 let res = netlist.try_unlink().unwrap().serialize(std::io::stdout());
141 if res.is_err() {
142 eprintln!("Failed to serialize netlist: {:?}", res.err());
143 }
144 }
145}