libreda_db/netlist/util.rs
1// Copyright (c) 2020-2021 Thomas Kramer.
2// SPDX-FileCopyrightText: 2022 Thomas Kramer
3//
4// SPDX-License-Identifier: AGPL-3.0-or-later
5
6//! Utility functions for dealing with netlists.
7
8use crate::prelude::TerminalId;
9use crate::traits::{NetlistBase, NetlistEdit};
10
11use std::borrow::Borrow;
12use std::collections::{HashMap, HashSet};
13use std::fmt;
14
15use itertools::Itertools;
16
17/// Copy the pin definitoins from a cell to another cell in another netlist.
18/// # Panics
19/// Panics if a pin name is already occupied at the destination cell.
20pub fn copy_pins<NS, ND>(
21 dest_netlist: &mut ND,
22 dest_cell: &ND::CellId,
23 source_netlist: &NS,
24 source_cell: &NS::CellId,
25) where
26 NS: NetlistBase,
27 ND: NetlistEdit,
28{
29 for source_pin in source_netlist.each_pin(source_cell) {
30 dest_netlist.create_pin(
31 dest_cell,
32 source_netlist.pin_name(&source_pin).to_string().into(),
33 source_netlist.pin_direction(&source_pin),
34 );
35 }
36}
37
38/// Non-modifying utility functions for netlists.
39/// Import the this trait to use the utility functions all types that implement the `NetlistBase` trait.
40pub trait NetlistUtil: NetlistBase {
41 /// Get the net that is attached to this terminal.
42 fn net_of_terminal(&self, terminal: &TerminalId<Self>) -> Option<Self::NetId> {
43 match terminal {
44 TerminalId::PinId(p) => self.net_of_pin(p),
45 TerminalId::PinInstId(p) => self.net_of_pin_instance(p),
46 }
47 }
48
49 /// Call a function for each terminal connected to this net.
50 fn for_each_terminal_of_net<F>(&self, net: &Self::NetId, mut f: F)
51 where
52 F: FnMut(TerminalId<Self>),
53 {
54 self.for_each_pin_of_net(net, |p| f(TerminalId::PinId(p)));
55 self.for_each_pin_instance_of_net(net, |p| f(TerminalId::PinInstId(p)));
56 }
57
58 /// Get a `Vec` with all terminal IDs connected to this net.
59 fn each_terminal_of_net_vec(&self, net: &Self::NetId) -> Vec<TerminalId<Self>> {
60 let mut v = Vec::new();
61 self.for_each_terminal_of_net(net, |c| v.push(c));
62 v
63 }
64
65 /// Iterate over all terminals of a net.
66 fn each_terminal_of_net<'a>(
67 &'a self,
68 net: &Self::NetId,
69 ) -> Box<dyn Iterator<Item = TerminalId<Self>> + 'a> {
70 Box::new(self.each_terminal_of_net_vec(net).into_iter())
71 }
72
73 /// Check if the net is either the constant LOW or HIGH.
74 fn is_constant_net(&self, net: &Self::NetId) -> bool {
75 let parent = self.parent_cell_of_net(net);
76 net == &self.net_zero(&parent) || net == &self.net_one(&parent)
77 }
78
79 /// Get all nets that are connected to the circuit instance.
80 fn nets_of_cell_instance(
81 &self,
82 inst: &Self::CellInstId,
83 ) -> Box<dyn Iterator<Item = Self::NetId> + '_> {
84 Box::new(
85 self.each_pin_instance(inst)
86 .flat_map(move |p| self.net_of_pin_instance(&p)),
87 )
88 }
89
90 /// Visit all circuit instances connected to this net.
91 /// An instance is touched not more than once.
92 fn for_each_circuit_instance_of_net<F>(&self, net: &Self::NetId, mut f: F)
93 where
94 F: FnMut(Self::CellInstId),
95 {
96 let mut visited = HashSet::new();
97 self.for_each_pin_instance_of_net(net, |pin_inst| {
98 let inst = self.parent_of_pin_instance(&pin_inst);
99 if !visited.contains(&inst) {
100 f(inst);
101 } else {
102 visited.insert(inst);
103 }
104 })
105 }
106
107 /// Iterate over all circuit instances connected to this net.
108 /// An instance is touched not more than once.
109 fn each_circuit_instance_of_net_vec(&self, net: &Self::NetId) -> Vec<Self::CellInstId> {
110 let mut v = Vec::new();
111 self.for_each_circuit_instance_of_net(net, |c| v.push(c));
112 v
113 }
114
115 /// Write the netlist in a human readable form.
116 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117 let circuits = self.each_cell_vec();
118 // circuits.sort_by_key(|c| c.id());
119 for c in &circuits {
120 let circuit_name = self.cell_name(c);
121 let circuit_instances = self.each_cell_instance_vec(c);
122 // circuit_instances.sort_by_key(|c| c.id());
123
124 // Get pin names together with the net they are connected to.
125 let pin_names = self
126 .each_pin(c)
127 .map(|pin| {
128 let pin_name = self.pin_name(&pin);
129 let net = self.net_of_pin(&pin);
130 let net_name: Option<String> = net.map(|n| {
131 self.net_name(&n)
132 .map(|n| n.into())
133 .unwrap_or("<unnamed>".into())
134 }); // TODO: Create a name.
135 format!("{}={:?}", pin_name, net_name)
136 })
137 .join(" ");
138
139 writeln!(f, ".subckt {} {}", circuit_name, pin_names)?;
140 for inst in &circuit_instances {
141 // fmt::Debug::fmt(Rc::deref(&c), f)?;
142 let sub_name: String = self
143 .cell_instance_name(inst)
144 .map(|n| n.into())
145 .unwrap_or("<unnamed>".into()); // TODO: Create a name.
146 let sub_template = self.template_cell(inst);
147 let template_name = self.cell_name(&sub_template);
148 let nets = self
149 .each_pin_instance(inst)
150 .map(|p| {
151 let pin = self.template_pin(&p);
152 let pin_name = self.pin_name(&pin);
153 let net = self.net_of_pin_instance(&p);
154 let net_name: Option<String> = net.map(|n| {
155 self.net_name(&n)
156 .map(|n| n.into())
157 .unwrap_or("<unnamed>".into())
158 });
159 format!("{}={:?}", pin_name, net_name)
160 })
161 .join(" ");
162 writeln!(f, " X{} {} {}", sub_name, template_name, nets)?;
163 }
164 writeln!(f, ".ends {}\n", circuit_name)?;
165 }
166 fmt::Result::Ok(())
167 }
168}
169
170impl<N: NetlistBase> NetlistUtil for N {}
171
172/// Modifying utility functions for netlists.
173/// Import the this trait to use the utility functions all types that implement the `NetlistBase` trait.
174pub trait NetlistEditUtil: NetlistEdit {
175 /// Connect a terminal to a net.
176 /// Returns the old connected net, if any.
177 fn connect_terminal(
178 &mut self,
179 terminal: &TerminalId<Self>,
180 net: Option<Self::NetId>,
181 ) -> Option<Self::NetId> {
182 match terminal {
183 TerminalId::PinId(p) => self.connect_pin(p, net),
184 TerminalId::PinInstId(p) => self.connect_pin_instance(p, net),
185 }
186 }
187
188 /// Disconnect the terminal from any connected net.
189 /// Returns the old connected net, if any.
190 fn disconnect_terminal(&mut self, terminal: &TerminalId<Self>) -> Option<Self::NetId> {
191 self.connect_terminal(terminal, None)
192 }
193
194 /// Take all terminals that are connected to `old_net` and connect them to `new_net` instead.
195 /// The old net is no longer used and removed.
196 ///
197 /// This is a default implementation that can possibly be implemented more efficiently for a concrete
198 /// netlist type.
199 fn replace_net(&mut self, old_net: &Self::NetId, new_net: &Self::NetId) {
200 if old_net == new_net {
201 // Nothing needs to be done.
202 } else {
203 // Check that the nets live in this circuit.
204 assert_eq!(
205 self.parent_cell_of_net(old_net),
206 self.parent_cell_of_net(new_net),
207 "Old net and new net must live in the same cell."
208 );
209
210 // Get terminals connected to the old net.
211 let terminals: Vec<_> = self.each_pin_of_net(old_net).collect();
212 // Connect each terminal to the new net.
213 for pin in terminals {
214 self.connect_pin(&pin, Some(new_net.clone()));
215 }
216 // Get terminals connected to the old net.
217 let terminals: Vec<_> = self.each_pin_instance_of_net(old_net).collect();
218 // Connect each terminal to the new net.
219 for pin in terminals {
220 self.connect_pin_instance(&pin, Some(new_net.clone()));
221 }
222
223 // Remove the now unused old net.
224 self.remove_net(old_net);
225 }
226 }
227
228 /// Replace the circuit instance with its contents. Remove the circuit instance afterwards.
229 /// Does not purge nets nor unconnected instances.
230 /// So there could be unconnected nets or unconnected instances.
231 ///
232 /// Nets keep their names if possible. If the net name already exists in this circuit, the name will
233 /// be set to `None`.
234 ///
235 /// The content of the circuit instance will be renamed by appending the names like a path.
236 fn flatten_circuit_instance(&mut self, circuit_instance: &Self::CellInstId) {
237 // Get the template circuit.
238 let template = self.template_cell(circuit_instance);
239 let parent_circuit = self.parent_cell(circuit_instance);
240
241 assert_ne!(
242 template, parent_circuit,
243 "Recursive instances are not allowed."
244 ); // Should not happen.
245
246 // Mapping from old to new nets.
247 let mut net_mapping: HashMap<Self::NetId, Self::NetId> = HashMap::new();
248
249 // Get or create a new net as an equivalent of the old.
250 let mut get_new_net = |netlist: &mut Self, old_net: &Self::NetId| -> Self::NetId {
251 if let Some(net_net) = net_mapping.get(old_net) {
252 net_net.clone()
253 } else {
254 // Get the name of the net.
255 let net_name = netlist.net_name(old_net);
256 // Resolve net name collisions.
257 // It is possible that the net name already exists in this circuit.
258 let net_name = net_name.filter(|net_name| {
259 // Use the given name only if it does not exist yet.
260 netlist
261 .net_by_name(&parent_circuit, net_name.borrow())
262 .is_none()
263 });
264
265 // Create the new net.
266 let new_net = netlist.create_net(&parent_circuit, net_name);
267 // Remember the mapping old_net -> net_net.
268 net_mapping.insert(old_net.clone(), new_net.clone());
269 new_net
270 }
271 };
272
273 // Constant HIGH and LOW nets are special cases.
274 // Connect previous constant nets to the equivalent constant nets of the parent cell.
275 let new_net_zero = get_new_net(self, &self.net_zero(&template));
276 let new_net_one = get_new_net(self, &self.net_one(&template));
277
278 // Copy all sub instances into this circuit.
279 // And connect their pins to copies of the original nets.
280 let all_instances = self.each_cell_instance_vec(&template);
281 for sub in all_instances {
282 let sub_template = self.template_cell(&sub);
283
284 let new_name = if let (Some(sub_instance_name), Some(inst_name)) = (
285 self.cell_instance_name(&sub),
286 self.cell_instance_name(circuit_instance),
287 ) {
288 // Construct name for the new sub instance.
289 // Something like: INSTANCE_TO_BE_FLATTENED:SUB_INSTANCE{_COUNTER}
290 {
291 let mut new_name = format!("{}:{}", inst_name, sub_instance_name);
292 let mut i = 0;
293 // It is possible that the instance name already exists in this circuit.
294 // If this name too already exists, append a counter.
295 while self
296 .cell_instance_by_name(&parent_circuit, &new_name)
297 .is_some()
298 {
299 new_name = format!("{}:{}_{}", inst_name, sub_instance_name, i);
300 i += 1;
301 }
302 Some(new_name)
303 }
304 } else {
305 None
306 };
307 let new_inst = self.create_cell_instance(
308 &parent_circuit,
309 &sub_template,
310 new_name.map(|n| n.into()),
311 );
312
313 // Re-connect pins to copies of the original nets.
314 // Loop over old/new pin instances.
315 let pin_mapping: Vec<_> = self
316 .each_pin_instance(&sub)
317 .zip(self.each_pin_instance(&new_inst))
318 .collect();
319 for (old_pin, new_pin) in pin_mapping {
320 // Sanity check: Ordering of the pin instances in both cell instances must be consistent.
321 debug_assert_eq!(
322 self.template_pin(&old_pin),
323 self.template_pin(&new_pin),
324 "Unexpected pin ordering."
325 );
326
327 // Get net on old pin.
328 if let Some(old_net) = self.net_of_pin_instance(&old_pin) {
329 let new_net = get_new_net(self, &old_net);
330 self.connect_pin_instance(&new_pin, Some(new_net));
331 }
332 }
333 }
334
335 // Connect the newly created sub-instances and nets to this circuit
336 // according to the old connections to the instance which is about to be flattened.
337 {
338 // First create the mapping from inner nets to outer nets.
339 // This is necessary for the case when multiple internal pins are connected to the same
340 // internal net.
341 let mut net_replacement_mapping: HashMap<_, _> = self
342 .each_pin_instance_vec(circuit_instance)
343 .into_iter()
344 .filter_map(|old_pin| {
345 let outer_net = self.net_of_pin_instance(&old_pin);
346 let inner_old_net = self.net_of_pin(&self.template_pin(&old_pin));
347 // If the pin was either not connected on the outside or not connected inside, nothing
348 // needs to be done.
349 if let (Some(outer_net), Some(inner_old_net)) = (outer_net, inner_old_net) {
350 // Get the new copy of the inner net.
351 let inner_new_net = get_new_net(self, &inner_old_net);
352 // Attach the new inner net to the outer net (by replacement).
353 if inner_new_net != outer_net {
354 Some((inner_new_net, outer_net))
355 } else {
356 // If the nets are the same, no replacement is necessary.
357 // This can happen for LOW and HIGH nets, since the mapping
358 // is already correct.
359 None
360 }
361 } else {
362 // Inner and outer pin were not connected, nothing needs to be done.
363 None
364 }
365 })
366 .collect();
367
368 // Handle special cases: LOW and HIGH nets.
369 net_replacement_mapping.insert(new_net_zero, self.net_zero(&parent_circuit));
370 net_replacement_mapping.insert(new_net_one, self.net_one(&parent_circuit));
371
372 // Make the net replacement.
373 net_replacement_mapping
374 .iter()
375 .for_each(|(inner_new_net, outer_net)| self.replace_net(inner_new_net, outer_net));
376 //
377 // // Handle special cases: LOW and HIGH nets.
378 // self.replace_net(&new_net_zero, &self.net_zero(&parent_circuit));
379 // self.replace_net(&new_net_one, &self.net_one(&parent_circuit));
380 }
381
382 // Remove old instance.
383 self.remove_cell_instance(circuit_instance);
384
385 // TODO: Clean-up.
386 // self.purge_nets();
387 // Remove unconnected instances.
388 }
389
390 /// Flatten all instances of this circuit by replacing them with their content.
391 /// Remove the circuit from the netlist afterwards.
392 /// For top level circuits this is equivalent to removing them.
393 fn flatten_circuit(&mut self, circuit: &Self::CellId) {
394 // TODO: Assert that the circuit lives in this netlist.
395 // Get all instances of the circuit.
396
397 // Flatten all instances of the circuit.
398 for r in self.each_cell_reference_vec(circuit) {
399 self.flatten_circuit_instance(&r);
400 }
401
402 debug_assert_eq!(
403 self.each_cell_reference(circuit).count(),
404 0,
405 "Circuit should not have any references anymore."
406 );
407
408 // Remove the cell.
409 self.remove_cell(circuit);
410 }
411
412 /// Delete all unconnected nets in this circuit.
413 /// Return number of purged nets.
414 fn purge_nets_in_circuit(&mut self, circuit_id: &Self::CellId) -> usize {
415 let high = self.net_one(circuit_id);
416 let low = self.net_zero(circuit_id);
417 let mut unused = Vec::new();
418 self.for_each_internal_net(circuit_id, |n| {
419 // Purge floating nets but keep the constant-value nets.
420 if self.num_net_terminals(&n) == 0 && n != high && n != low {
421 unused.push(n)
422 }
423 });
424
425 unused.iter().for_each(|n| self.remove_net(n));
426
427 unused.len()
428 }
429
430 /// Delete all unconnected nets in all circuits.
431 /// Return number of purged nets.
432 fn purge_nets(&mut self) -> usize {
433 let all_circuits = self.each_cell_vec();
434 all_circuits
435 .iter()
436 .map(|c| self.purge_nets_in_circuit(c))
437 .sum()
438 }
439
440 /// Create names for all unnamed nets in the specified circuit.
441 /// The names will consist of the `prefix` and an appended number.
442 /// After calling this method, no net inside this circuit will be unnamed.
443 fn create_net_names_in_circuit(&mut self, circuit_id: &Self::CellId, prefix: &str) {
444 let all_nets = self.each_internal_net_vec(circuit_id);
445 let unnamed_nets: Vec<_> = all_nets
446 .iter()
447 .filter(|net| self.net_name(net).is_none())
448 .collect();
449
450 if !unnamed_nets.is_empty() {
451 let mut id_counter = 0;
452 for unnamed_net in unnamed_nets {
453 // Generate a new name.
454 let net_name = loop {
455 let net_name = format!("{}{}", prefix, id_counter);
456 id_counter += 1;
457 if self.net_by_name(circuit_id, &net_name).is_none() {
458 break net_name;
459 }
460 };
461
462 let old_name = self.rename_net(unnamed_net, Some(net_name.into()));
463 debug_assert!(old_name.is_none());
464 }
465 }
466 }
467}
468
469impl<N: NetlistEdit + ?Sized> NetlistEditUtil for N {}