use crate::traits::{NetlistBase, NetlistEdit};
use std::collections::{HashMap, HashSet};
use std::borrow::Borrow;
use std::fmt;
use itertools::Itertools;
pub trait NetlistUtil: NetlistBase {
fn is_constant_net(&self, net: &Self::NetId) -> bool {
let parent = self.parent_cell_of_net(net);
net == &self.net_zero(&parent) || net == &self.net_one(&parent)
}
fn nets_of_cell_instance(&self, inst: &Self::CellInstId) -> Box<dyn Iterator<Item=Self::NetId> + '_> {
Box::new(self.each_pin_instance(inst)
.flat_map(move |p| self.net_of_pin_instance(&p)))
}
fn for_each_circuit_instance_of_net<F>(&self, net: &Self::NetId, mut f: F) where F: FnMut(Self::CellInstId) -> () {
let mut visited = HashSet::new();
self.for_each_pin_instance_of_net(net, |pin_inst| {
let inst = self.parent_of_pin_instance(&pin_inst);
if !visited.contains(&inst) {
f(inst);
} else {
visited.insert(inst);
}
})
}
fn each_circuit_instance_of_net_vec(&self, net: &Self::NetId) -> Vec<Self::CellInstId> {
let mut v = Vec::new();
self.for_each_circuit_instance_of_net(net, |c| v.push(c.clone()));
v
}
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let circuits = self.each_cell_vec();
for c in &circuits {
let circuit_name = self.cell_name(c);
let circuit_instances = self.each_cell_instance_vec(c);
let pin_names = self.each_pin(c)
.map(|pin| {
let pin_name = self.pin_name(&pin);
let net = self.net_of_pin(&pin);
let net_name: Option<String> = net.
map(|n| self.net_name(&n)
.map(|n| n.into())
.unwrap_or("<unnamed>".into())); format!("{}={:?}", pin_name, net_name)
}).join(" ");
writeln!(f, ".subckt {} {}", circuit_name, pin_names)?;
for inst in &circuit_instances {
let sub_name: String = self.cell_instance_name(inst)
.map(|n| n.into())
.unwrap_or("<unnamed>".into()); let sub_template = self.template_cell(inst);
let template_name = self.cell_name(&sub_template);
let nets = self.each_pin_instance(inst)
.map(|p| {
let pin = self.template_pin(&p);
let pin_name = self.pin_name(&pin);
let net = self.net_of_pin_instance(&p);
let net_name: Option<String> = net.
map(|n| self.net_name(&n)
.map(|n| n.into())
.unwrap_or("<unnamed>".into()));
format!("{}={:?}", pin_name, net_name)
}).join(" ");
writeln!(f, " X{} {} {}", sub_name, template_name, nets)?;
}
writeln!(f, ".ends {}\n", circuit_name)?;
}
fmt::Result::Ok(())
}
}
impl<N: NetlistBase> NetlistUtil for N {}
pub trait NetlistEditUtil: NetlistEdit {
fn replace_net(&mut self, old_net: &Self::NetId, new_net: &Self::NetId) {
if old_net == new_net {
} else {
assert_eq!(self.parent_cell_of_net(old_net), self.parent_cell_of_net(new_net),
"Old net and new net must live in the same cell.");
let terminals: Vec<_> = self.each_pin_of_net(&old_net).collect();
for pin in terminals {
self.connect_pin(&pin, Some(new_net.clone()));
}
let terminals: Vec<_> = self.each_pin_instance_of_net(&old_net).collect();
for pin in terminals {
self.connect_pin_instance(&pin, Some(new_net.clone()));
}
self.remove_net(&old_net);
}
}
fn flatten_circuit_instance(&mut self, circuit_instance: &Self::CellInstId) {
let template = self.template_cell(circuit_instance);
let parent_circuit = self.parent_cell(circuit_instance);
assert_ne!(template, parent_circuit, "Recursive instances are not allowed.");
let mut net_mapping: HashMap<Self::NetId, Self::NetId> = HashMap::new();
let mut get_new_net = |netlist: &mut Self, old_net: &Self::NetId| -> Self::NetId {
if let Some(net_net) = net_mapping.get(old_net) {
net_net.clone()
} else {
let net_name = netlist.net_name(old_net);
let net_name = if let Some(net_name) = net_name {
if let Some(_) = netlist.net_by_name(&parent_circuit, net_name.borrow()) {
None
} else {
Some(net_name)
}
} else {
None
};
let new_net = netlist.create_net(&parent_circuit, net_name);
net_mapping.insert(old_net.clone(), new_net.clone());
new_net
}
};
let new_net_zero = get_new_net(self, &self.net_zero(&template));
let new_net_one = get_new_net(self, &self.net_one(&template));
let all_instances = self.each_cell_instance_vec(&template);
for sub in all_instances {
let sub_template = self.template_cell(&sub);
let new_name = if let (Some(sub_instance_name), Some(inst_name)) =
(self.cell_instance_name(&sub), self.cell_instance_name(circuit_instance)) {
{
let mut new_name = format!("{}:{}", inst_name, sub_instance_name);
let mut i = 0;
while self.cell_instance_by_name(&parent_circuit, &new_name).is_some() {
new_name = format!("{}:{}_{}", inst_name, sub_instance_name, i);
i += 1;
}
Some(new_name)
}
} else {
None
};
let new_inst = self.create_cell_instance(&parent_circuit, &sub_template,
new_name.map(|n| n.into()));
let pin_mapping: Vec<_> = self.each_pin_instance(&sub)
.zip(self.each_pin_instance(&new_inst))
.collect();
for (old_pin, new_pin) in pin_mapping {
debug_assert_eq!(self.template_pin(&old_pin), self.template_pin(&new_pin),
"Unexpected pin ordering.");
if let Some(old_net) = self.net_of_pin_instance(&old_pin) {
let new_net = get_new_net(self, &old_net);
self.connect_pin_instance(&new_pin, Some(new_net));
}
}
}
{
let mut net_replacement_mapping: HashMap<_, _> =
self.each_pin_instance_vec(circuit_instance)
.into_iter()
.filter_map(|old_pin| {
let outer_net = self.net_of_pin_instance(&old_pin);
let inner_old_net = self.net_of_pin(&self.template_pin(&old_pin));
if let (Some(outer_net), Some(inner_old_net)) = (outer_net, inner_old_net) {
let inner_new_net = get_new_net(self, &inner_old_net);
if inner_new_net != outer_net {
Some((inner_new_net, outer_net))
} else {
None
}
} else {
None
}
})
.collect();
net_replacement_mapping.insert(new_net_zero, self.net_zero(&parent_circuit));
net_replacement_mapping.insert(new_net_one, self.net_one(&parent_circuit));
net_replacement_mapping.iter()
.for_each(|(inner_new_net, outer_net)|
self.replace_net(inner_new_net, outer_net)
);
}
self.remove_cell_instance(circuit_instance);
}
fn flatten_circuit(&mut self, circuit: &Self::CellId) {
for r in self.each_cell_reference_vec(circuit) {
self.flatten_circuit_instance(&r);
}
debug_assert_eq!(self.each_cell_reference(circuit).count(), 0,
"Circuit should not have any references anymore.");
self.remove_cell(circuit);
}
fn purge_nets_in_circuit(&mut self, circuit_id: &Self::CellId) -> usize {
let high = self.net_one(circuit_id);
let low = self.net_zero(circuit_id);
let mut unused = Vec::new();
self.for_each_internal_net(circuit_id, |n| {
if self.num_net_terminals(&n) == 0 && n != high && n != low {
unused.push(n)
}
});
unused.iter()
.for_each(|n| self.remove_net(n));
return unused.len();
}
fn purge_nets(&mut self) -> usize {
let all_circuits = self.each_cell_vec();
all_circuits.iter()
.map(|c| self.purge_nets_in_circuit(c))
.sum()
}
}
impl<N: NetlistEdit + ?Sized> NetlistEditUtil for N {}