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 {}