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}