netlist_db/
utlis.rs

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