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}