netlist_db/
utlis.rs

1use crate::{Subckt, instance::InstanceCtx};
2use indexmap::IndexMap;
3use itertools::Itertools as _;
4use std::{borrow::Cow, collections::HashMap, iter::once, ops::Deref as _};
5
6impl<'s> Subckt<'s> {
7    pub fn append<'a>(
8        cktname: &str,
9        need_skip: impl Copy + Fn(&str) -> bool,
10        inst_path: &mut Vec<&'a Cow<'s, str>>,
11        include_subckts: &mut Vec<&'a IndexMap<String, Self>>,
12        internal_nodes: &mut Vec<String>,
13        append_subckts: &mut Vec<&'a Self>,
14    ) -> Result<(), String> {
15        if need_skip(cktname) {
16            return Ok(());
17        }
18        for (idx, include) in include_subckts.iter().enumerate().rev() {
19            if let Some(ckt) = include.get(&cktname.to_lowercase()) {
20                let mut nodes_map =
21                    ckt.ast
22                        .instance
23                        .iter()
24                        .fold(HashMap::new(), |mut nodes_map, inst| {
25                            inst.ctx.append_nodes(&mut nodes_map);
26                            nodes_map
27                        });
28                for port in &ckt.ports {
29                    _ = nodes_map.remove(&port.to_lowercase());
30                }
31                internal_nodes.extend(
32                    nodes_map
33                        .into_values()
34                        .map(|n| inst_path.iter().copied().chain(once(n)).join(".")),
35                );
36                if idx == 0 {
37                    // idx==0 means in top
38                    append_subckts.push(ckt);
39                }
40                include_subckts.push(&ckt.ast.subckt);
41                for inst in &ckt.ast.instance {
42                    if let InstanceCtx::Subckt(ckt) = &inst.ctx {
43                        inst_path.push(&inst.name);
44                        Self::append(
45                            &ckt.cktname,
46                            need_skip,
47                            inst_path,
48                            include_subckts,
49                            internal_nodes,
50                            append_subckts,
51                        )?;
52                        inst_path.pop();
53                    }
54                }
55                include_subckts.pop();
56                return Ok(());
57            }
58        }
59        Err(inst_path
60            .iter()
61            .map(|inst| (*inst).deref())
62            .chain(once(cktname))
63            .join("."))
64    }
65    // fn flatten_instances(
66    //     &self,
67    //     inst_name: &Cow<'s, str>,
68    //     inst_ports: &Vec<Cow<'s, str>>,
69    //     inst_params: &Vec<KeyValue<'s>>,
70    // ) -> Vec<Instance<'s>> {
71    //     let node_name_mapping: HashMap<_, _> = zip_eq(&self.ports, inst_ports)
72    //         .map(|(port, inst_port)| (port.to_lowercase(), inst_port))
73    //         .collect();
74    //     let get_node = |n: &Cow<'s, str>| -> Cow<'s, str> {
75    //         if let Some(&inst_port) = node_name_mapping.get(&n.to_lowercase()) {
76    //             inst_port.clone()
77    //         } else {
78    //             n.clone()
79    //         }
80    //     };
81    //     let get_value = |v: &Value<'s>| -> Value<'s> { v.clone() };
82    //     self.ast
83    //         .instance
84    //         .iter()
85    //         .map(|inst| Instance {
86    //             name: format!("{}.{}", inst.name, inst_name).into(),
87    //             ctx: match &inst.ctx {
88    //                 InstanceCtx::Resistor(r) => InstanceCtx::Resistor(Resistor {
89    //                     n1: get_node(&r.n1),
90    //                     n2: get_node(&r.n2),
91    //                     value: get_value(&r.value),
92    //                 }),
93    //                 InstanceCtx::Capacitor(c) => InstanceCtx::Capacitor(Capacitor {
94    //                     n1: get_node(&c.n1),
95    //                     n2: get_node(&c.n2),
96    //                     value: get_value(&c.value),
97    //                 }),
98    //                 InstanceCtx::Inductor(i) => InstanceCtx::Inductor(Inductor {
99    //                     n1: get_node(&i.n1),
100    //                     n2: get_node(&i.n2),
101    //                     value: get_value(&i.value),
102    //                 }),
103    //                 InstanceCtx::Voltage(v) => InstanceCtx::Voltage(Voltage {
104    //                     n1: get_node(&v.n1),
105    //                     n2: get_node(&v.n2),
106    //                     source: v.source.clone(),
107    //                 }),
108    //                 InstanceCtx::Current(c) => InstanceCtx::Current(Current {
109    //                     n1: get_node(&c.n1),
110    //                     n2: get_node(&c.n2),
111    //                     source: c.source.clone(),
112    //                 }),
113    //                 InstanceCtx::MOSFET(m) => todo!(),
114    //                 InstanceCtx::BJT(b) => todo!(),
115    //                 InstanceCtx::Diode(d) => todo!(),
116    //                 InstanceCtx::Subckt(s) => todo!(),
117    //                 InstanceCtx::Unknown {
118    //                     r#type,
119    //                     nodes,
120    //                     params,
121    //                 } => todo!(),
122    //             },
123    //         })
124    //         .collect()
125    // }
126    // pub fn flatten(&mut self, env_subckts: &mut Vec<Rc<IndexMap<String, Subckt<'s>>>>) {
127    //     let mut new_inst = Vec::new();
128    //     for subckt in self.ast.subckt.values_mut() {
129    //         subckt.flatten(env_subckts);
130    //     }
131    //     // self.params
132    //     env_subckts.push(self.ast.subckt);
133    //     for inst in mem::take(&mut self.ast.instance) {
134    //         if let InstanceCtx::Subckt(a) = &inst.ctx {
135    //         } else {
136    //             new_inst.push(inst);
137    //         }
138    //     }
139    // }
140}
141
142#[cfg(test)]
143pub(crate) mod test {
144    use std::path::PathBuf;
145
146    use crate::{FileId, Subckt, parser::parse_top_multi};
147
148    pub(crate) fn init_logger() {
149        #[cfg(not(feature = "tracing"))]
150        {
151            _ = simple_logger::SimpleLogger::new().init();
152        }
153        #[cfg(feature = "tracing")]
154        {
155            let subscriber = tracing_subscriber::FmtSubscriber::builder()
156                // .with_ansi(colored::control::SHOULD_COLORIZE.should_colorize())
157                .with_max_level(tracing::Level::DEBUG)
158                .with_target(false)
159                .with_file(true)
160                .with_line_number(true)
161                .with_timer(tracing_subscriber::fmt::time::ChronoLocal::new(
162                    "%FT%T".to_owned(),
163                ))
164                .finish();
165            _ = tracing::subscriber::set_global_default(subscriber);
166        }
167    }
168
169    #[tokio::test]
170    async fn test_append() {
171        init_logger();
172        let (parsed, files) = parse_top_multi(
173            [FileId::Include {
174                path: PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/async_sync_dff.cdl"),
175            }]
176            .into_iter(),
177        )
178        .await;
179        let (ast, has_err) = files.build(parsed);
180        assert!(!has_err);
181        let mut internal_nodes = Vec::new();
182        let mut append_subckts = Vec::new();
183        Subckt::append(
184            "ASYNC_SYNC_DFF",
185            |_s| false,
186            &mut Vec::new(),
187            &mut vec![&ast.subckt],
188            &mut internal_nodes,
189            &mut append_subckts,
190        )
191        .unwrap();
192        dbg!(internal_nodes);
193        for append_subckt in append_subckts {
194            println!("{append_subckt}");
195        }
196    }
197}