use super::prelude::*;
use std::cell::RefCell;
use std::rc::{Weak, Rc};
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use genawaiter::rc::Gen;
use itertools::Itertools;
use std::ops::Deref;
use std::borrow::Borrow;
use std::collections::hash_map::Values;
use std::fmt;
pub struct Circuit {
pub(super) name: String,
id: CircuitIndex,
pub(super) self_reference: RefCell<Weak<Circuit>>,
pins: Vec<Rc<Pin>>,
nets: RefCell<HashMap<NetIndex, Rc<Net>>>,
nets_by_name: RefCell<HashMap<String, NetIndex>>,
net_index_generator: RefCell<NetIndexGenerator>,
circuit_instances: RefCell<HashMap<CircuitInstIndex, Rc<CircuitInstance>>>,
circuit_instances_by_name: RefCell<HashMap<String, CircuitInstIndex>>,
circuit_instance_index_generator: RefCell<CircuitInstIndexGenerator>,
circuit_references: RefCell<HashSet<Rc<CircuitInstance>>>,
dependencies: RefCell<HashMap<CircuitIndex, (Weak<Circuit>, usize)>>,
dependent_circuits: RefCell<HashMap<CircuitIndex, (Weak<Circuit>, usize)>>,
}
impl fmt::Debug for Circuit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Circuit")
.field("name", &self.name)
.field("id", &self.id.value())
.field("pins", &self.pins.iter().map(|p| p.name()).collect_vec())
.finish()
}
}
impl fmt::Display for Circuit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut circuit_instances = self.each_instance().collect_vec();
circuit_instances.sort_by_key(|c| c.id());
let pin_names = self.each_pin()
.map(|p| {
let netname = p.internal_net().map(|n| n.create_name());
format!("{}={:?}", p.name(), netname)
}).join(" ");
writeln!(f, ".subckt {} {}", self.name, pin_names)?;
for c in circuit_instances {
let sub_name = c.name().cloned()
.unwrap_or_else(|| format!("__{}", c.id));
let sub_template = c.circuit_ref().upgrade().unwrap()
.name().clone();
let nets = c.each_pin_instance()
.map(|p| {
let netname = p.net().map(|n| n.create_name());
format!("{}={:?}", p.pin().name(), netname)
}).join(" ");
writeln!(f, " X{} {} {}", sub_name, sub_template, nets)?;
}
writeln!(f, ".ends {}\n", self.name)?;
fmt::Result::Ok(())
}
}
impl Eq for Circuit {}
impl PartialEq for Circuit {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Hash for Circuit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl Circuit {
pub(super) fn new(circuit_id: CircuitIndex, name: String, pins: Vec<Pin>) -> Self {
let pins = pins.into_iter().enumerate()
.map(|(pin_id, mut p)| {
p.id = pin_id;
p.parent_circuit_id = circuit_id;
Rc::new(p)
})
.collect();
Circuit {
name,
id: circuit_id,
self_reference: Default::default(),
pins,
nets: Default::default(),
nets_by_name: Default::default(),
net_index_generator: RefCell::new(NetIndexGenerator::new(2)),
circuit_instances: Default::default(),
circuit_instances_by_name: Default::default(),
circuit_instance_index_generator: Default::default(),
circuit_references: Default::default(),
dependencies: Default::default(),
dependent_circuits: Default::default(),
}
}
pub fn name(&self) -> &String {
&self.name
}
pub fn connect_pin_by_id(&self, pin_id: usize, net: Option<Rc<Net>>) -> Option<Rc<Net>> {
let pin = self.pins.get(pin_id).expect("Pin with this index does not exist.");
self.connect_pin(&pin, net)
}
pub fn connect_pin(&self, pin: &Rc<Pin>, net: Option<Rc<Net>>) -> Option<Rc<Net>> {
assert_eq!(pin.parent_circuit_id, self.id, "Pin does not live in this circuit.");
debug_assert!(pin.parent_circuit().ptr_eq(&self.self_reference()));
if let Some(net) = &net {
assert!(net.parent_circuit.ptr_eq(&self.self_reference()),
"Net does not live in this circuit.");
}
let old_net = pin.internal_net();
if let Some(old_net) = &old_net {
old_net.pins.borrow_mut().remove(&pin.clone());
}
if let Some(net) = &net {
net.pins.borrow_mut()
.insert(pin.clone());
}
pin.internal_net.replace(net);
old_net
}
fn net_of_logic_constant(&self, constant: usize) -> Rc<Net> {
let net_index = NetIndex::new(constant);
self.net_by_index(&net_index)
.unwrap_or_else(|| {
let net = Rc::new(
Net {
id: net_index,
name: Default::default(),
parent_circuit: self.self_reference.borrow().clone(),
pins: Default::default(),
pin_instances: Default::default(),
}
);
self.nets.borrow_mut().insert(net_index, net.clone());
net
})
}
pub fn net_zero(&self) -> Rc<Net> {
self.net_of_logic_constant(0)
}
pub fn net_one(&self) -> Rc<Net> {
self.net_of_logic_constant(1)
}
pub fn create_net<S: Into<String>>(&self, name: Option<S>) -> Rc<Net> {
let name = name.map(|n| n.into());
let net_index = self.net_index_generator.borrow_mut().next();
if let Some(name) = &name {
assert!(!self.nets_by_name.borrow().contains_key(name), "Net name already exists.");
self.nets_by_name.borrow_mut().insert(name.clone(), net_index);
}
let net = Rc::new(
Net {
id: net_index,
name: RefCell::new(name),
parent_circuit: self.self_reference.borrow().clone(),
pins: Default::default(),
pin_instances: Default::default(),
}
);
self.nets.borrow_mut().insert(net_index, net.clone());
net
}
pub fn each_circuit_dependency(&self) -> impl Iterator<Item=Rc<Circuit>> + '_ {
let generator = Gen::new(|co| async move {
for (dep, _counter) in self.dependencies.borrow().values() {
co.yield_(dep.upgrade().unwrap()).await;
}
});
generator.into_iter()
}
pub fn each_dependent_circuit(&self) -> impl Iterator<Item=Rc<Circuit>> + '_ {
let generator = Gen::new(|co| async move {
for (dep, _counter) in self.dependent_circuits.borrow().values() {
co.yield_(dep.upgrade().unwrap()).await;
}
});
generator.into_iter()
}
pub fn create_circuit_instance<S: Into<String>>(&self, template_circuit: &Rc<Circuit>, name: Option<S>) -> Rc<CircuitInstance> {
let name = name.map(|s| s.into());
if let Some(name) = &name {
if self.circuit_instances_by_name.borrow().contains_key(name) {
panic!(format!("Instance with name '{}' already exists.", name));
}
}
{
let mut stack: Vec<Rc<Circuit>> = vec![self.self_reference().upgrade().unwrap()];
while let Some(c) = stack.pop() {
if c.eq(template_circuit) {
panic!("Cannot create recursive instances.");
}
c.dependent_circuits.borrow().values()
.map(|(dep, _)| dep.upgrade().unwrap())
.for_each(|dep| stack.push(dep));
}
}
let index = self.circuit_instance_index_generator.borrow_mut().next();
let pin_instances: Vec<_> = template_circuit.pins.iter()
.map(|pin|
Rc::new(PinInstance {
circuit_instance_id: index,
circuit_instance: Default::default(),
pin: pin.clone(),
net: Default::default(),
})
).collect();
let inst = CircuitInstance {
name: name.clone(),
circuit: Rc::downgrade(template_circuit),
circuit_id: template_circuit.id,
parent_circuit: self.self_reference(),
parent_circuit_id: self.id,
id: index,
pin_instances: pin_instances.clone(),
};
let inst = Rc::new(inst);
for pi in pin_instances {
pi.circuit_instance.replace(Rc::downgrade(&inst));
}
if let Some(name) = name {
self.circuit_instances_by_name.borrow_mut()
.insert(name, index);
}
self.circuit_instances.borrow_mut()
.insert(index, inst.clone());
{
let mut dependencies = self.dependencies.borrow_mut();
dependencies.entry(template_circuit.id)
.and_modify(|(_, c)| *c += 1)
.or_insert((Rc::downgrade(template_circuit), 1));
}
{
let mut dependent = template_circuit.dependent_circuits.borrow_mut();
dependent.entry(self.id)
.and_modify(|(_, c)| *c += 1)
.or_insert((self.self_reference(), 1));
}
let was_not_present = template_circuit.circuit_references.borrow_mut()
.insert(inst.clone());
debug_assert!(was_not_present, "Circuit instance with this index already existed!");
#[cfg(debug_assertions)] {
debug_assert_eq!(self.num_references(), self.dependent_circuits.borrow().values()
.map(|(_, n)| n).sum(), "self.num_references() is not consistent with the number of dependent circuits.");
debug_assert_eq!(template_circuit.num_references(), template_circuit.dependent_circuits.borrow().values()
.map(|(_, n)| n).sum(), "circuit.num_references() is not consistent with the number of dependent circuits.");
let dependencies = self.dependencies.borrow()
.values().map(|(c, _)| c.upgrade().unwrap().id()).sorted().collect_vec();
let dependencies_derived = self.each_instance()
.map(|c| c.circuit_id())
.unique().sorted().collect_vec();
debug_assert_eq!(dependencies, dependencies_derived);
}
inst
}
pub fn disconnect_pin_by_id(&self, pin_id: usize) -> () {
self.connect_pin_by_id(pin_id, None);
}
pub fn disconnect_pin(&self, pin: &Rc<Pin>) -> () {
self.connect_pin(pin, None);
}
pub fn for_each_child_recursive<F>(&self, f: F)
where F: Fn(&Rc<CircuitInstance>) {
for i in self.circuit_instances.borrow().values() {
f(i);
let circuit = i.circuit.upgrade().unwrap();
circuit.for_each_child_recursive(&f)
}
}
pub fn each_child_recursive(&self) -> impl Iterator<Item=Rc<CircuitInstance>> + '_ {
let generator = Gen::new(|co| async move {
let mut visited = HashSet::new();
let mut stack: Vec<_> = self.circuit_instances.borrow().values().cloned().collect();
while let Some(top) = stack.pop() {
co.yield_(top.clone()).await;
dbg!(stack.len());
visited.insert(top.clone());
let circuit: Rc<Circuit> = top.circuit.upgrade().unwrap();
for inst in circuit.circuit_instances.borrow().values().cloned() {
dbg!(&inst.name);
stack.push(inst)
}
}
});
generator.into_iter()
}
pub fn num_instances(&self) -> usize {
self.circuit_instances.borrow().len()
}
pub fn instances(&self) -> impl Deref<Target=HashMap<CircuitInstIndex, Rc<CircuitInstance>>> + '_ {
self.circuit_instances.borrow()
}
pub fn each_instance(&self) -> impl Iterator<Item=Rc<CircuitInstance>> + '_ {
let generator = Gen::new(|co| async move {
for e in self.circuit_instances.borrow().values().cloned() {
co.yield_(e).await;
}
});
generator.into_iter()
}
pub fn with_instance_iter<F, R>(&self, f: F) -> R
where F: FnOnce(Values<CircuitInstIndex, Rc<CircuitInstance>>) -> R,
{
f(self.circuit_instances.borrow().values())
}
pub fn references(&self) -> impl Deref<Target=HashSet<Rc<CircuitInstance>>> + '_ {
self.circuit_references.borrow()
}
pub fn num_references(&self) -> usize {
self.circuit_references.borrow().len()
}
pub fn has_references(&self) -> bool {
!self.circuit_references.borrow().is_empty()
}
pub fn each_reference(&self) -> impl Iterator<Item=Rc<CircuitInstance>> + '_ {
let generator = Gen::new(|co| async move {
for e in self.circuit_references.borrow().iter().cloned() {
co.yield_(e).await;
}
});
generator.into_iter()
}
pub fn with_reference_iter<F, R>(&self, f: F) -> R
where F: FnOnce(std::collections::hash_set::Iter<Rc<CircuitInstance>>) -> R,
{
f(self.circuit_references.borrow().iter())
}
#[inline]
pub fn nets(&self) -> impl Deref<Target=HashMap<NetIndex, Rc<Net>>> + '_ {
self.nets.borrow()
}
pub fn num_nets(&self) -> usize {
self.nets().len()
}
pub fn each_net(&self) -> impl Iterator<Item=Rc<Net>> + '_ {
let generator = Gen::new(|co| async move {
for n in self.nets().values().cloned() {
co.yield_(n).await;
}
});
generator.into_iter()
}
pub fn with_net_iter<F, R>(&self, f: F) -> R
where F: FnOnce(Values<NetIndex, Rc<Net>>) -> R,
{
f(self.nets().values())
}
pub fn each_pin(&self) -> impl Iterator<Item=&Rc<Pin>> + ExactSizeIterator {
self.pins.iter()
}
pub fn each_pin_vec(&self) -> Vec<Rc<Pin>> {
self.pins.to_vec()
}
pub fn flatten_circuit_instance(&self, circuit_instance: &Rc<CircuitInstance>) {
assert!(self.contains_instance(circuit_instance),
"Instance does not live in this circuit.");
let template = circuit_instance.circuit_ref().upgrade().unwrap();
let mut net_mapping: HashMap<Rc<Net>, Rc<Net>> = HashMap::new();
let mut get_new_net = |old_net: Rc<Net>| -> Rc<Net> {
if let Some(net_net) = net_mapping.get(&old_net) {
net_net.clone()
} else {
let net_name = old_net.name();
let net_name = if let Some(net_name) = net_name {
if let Some(_) = self.net_index_by_name(&net_name) {
None
} else {
Some(net_name)
}
} else {
None
};
let new_net = self.create_net(net_name);
net_mapping.insert(old_net.clone(), new_net.clone());
new_net
}
};
for sub in template.each_instance() {
let sub_template = sub.circuit_ref().upgrade().unwrap();
let new_name = if let (Some(sub_instance_name), Some(inst_name)) =
(sub.name(), circuit_instance.name()) {
{
let mut new_name = format!("{}:{}", inst_name, sub_instance_name);
let mut i = 0;
while self.circuit_instances_by_name.borrow().contains_key(&new_name) {
new_name = format!("{}:{}_{}", inst_name, sub_instance_name, i);
i += 1;
}
Some(new_name)
}
} else {
None
};
let new_inst = self.create_circuit_instance(&sub_template, new_name);
for (old_pin, new_pin)
in sub.each_pin_instance()
.zip(new_inst.each_pin_instance()) {
if let Some(old_net) = old_pin.net() {
let new_net = get_new_net(old_net);
new_pin.connect_net(Some(new_net));
}
}
}
{
let net_replacement_mapping: HashMap<_, _> = circuit_instance.each_pin_instance()
.filter_map(|old_pin| {
let outer_old_net = old_pin.net();
let inner_old_net = old_pin.pin().internal_net();
if let (Some(outer_net), Some(inner_old_net)) = (outer_old_net, inner_old_net) {
let inner_new_net = get_new_net(inner_old_net);
Some((inner_new_net, outer_net))
} else {
None
}
})
.collect();
net_replacement_mapping.iter()
.for_each(|(inner_new_net, outer_net)|
self.replace_net(inner_new_net, outer_net)
);
}
self.remove_circuit_instance(circuit_instance);
}
pub fn id(&self) -> CircuitIndex {
self.id
}
pub fn contains_instance(&self, circuit_instance: &Rc<CircuitInstance>) -> bool {
if let Some(parent) = circuit_instance.parent_circuit().upgrade() {
self.eq(&parent)
} else {
false
}
}
pub fn net_count(&self) -> usize {
self.nets().len()
}
pub fn net_by_index(&self, index: &NetIndex) -> Option<Rc<Net>> {
self.nets().get(index).cloned()
}
pub fn net_index_by_name<S: ?Sized>(&self, name: &S) -> Option<NetIndex>
where String: Borrow<S>,
S: Hash + Eq {
self.nets_by_name.borrow().get(name).cloned()
}
pub fn net_by_name<S: ?Sized>(&self, name: &S) -> Option<Rc<Net>>
where String: Borrow<S>,
S: Hash + Eq {
self.net_index_by_name(name)
.map(|i| self.net_by_index(&i).unwrap())
}
pub fn net_for_pin(&self, pin_id: usize) -> Option<Rc<Net>> {
self.pin_by_id(pin_id)
.expect("Pin does not exist.")
.internal_net()
}
pub fn pin_by_id(&self, pin_id: usize) -> Option<Rc<Pin>> {
self.pins.get(pin_id).cloned()
}
pub fn pin_by_name<N: ?Sized + Eq + Hash>(&self, pin_name: &N) -> Option<Rc<Pin>>
where String: Borrow<N> {
let pin = self.pins.iter()
.find(|p| p.name().borrow() == pin_name);
pin.cloned()
}
pub fn pin_count(&self) -> usize {
self.pins.len()
}
pub fn purge_nets(&self) -> usize {
let unused_nets: Vec<_> = self.each_net().into_iter()
.filter(|net| net.num_terminals() == 0).collect();
for net in &unused_nets {
self.remove_net(net)
}
unused_nets.len()
}
pub fn remove_net(&self, net: &Rc<Net>) -> () {
assert!(self.nets.borrow().contains_key(&net.id), "Net does not exist in this circuit.");
for terminal in net.each_terminal().collect_vec() {
match terminal {
TerminalRef::PinInstance(p) => {
let circuit_instance = self.circuit_instance_by_id(&p.circuit_instance_id).unwrap();
debug_assert!(circuit_instance.parent_circuit.ptr_eq(&self.self_reference()));
circuit_instance.disconnect_pin_by_id(p.id());
}
TerminalRef::Pin(p) => {
assert_eq!(p.parent_circuit_id, self.id);
debug_assert!(p.parent_circuit().ptr_eq(&self.self_reference()));
self.disconnect_pin_by_id(p.id);
}
}
}
assert_eq!(net.num_terminals(), 0, "Net must be floating now.");
self.nets.borrow_mut().remove(&net.id).unwrap();
}
pub(super) fn rename_net<S: Into<String>>(&self, net_index: NetIndex, name: Option<S>) {
let net = self.net_by_index(&net_index).expect("Net not found.");
let name: Option<String> = name.map(|n| n.into());
if let Some(name) = &name {
if let Some(other) = self.net_by_name(name) {
if other != net {
panic!("Net name already exists.")
} else {
return;
}
}
}
let maybe_old_name = net.name.replace(name.clone());
let mut nets_by_name = self.nets_by_name.borrow_mut();
if let Some(old_name) = maybe_old_name {
nets_by_name.remove(&old_name);
}
if let Some(name) = name {
nets_by_name.insert(name, net.id());
}
}
pub fn replace_net(&self, old_net: &Rc<Net>, new_net: &Rc<Net>) {
assert!(old_net.parent_circuit().ptr_eq(&self.self_reference()));
assert!(new_net.parent_circuit().ptr_eq(&self.self_reference()));
assert!(self.nets.borrow().contains_key(&old_net.id), "Old net does not exist in this circuit.");
assert!(self.nets.borrow().contains_key(&new_net.id), "New net does not exist in this circuit.");
let terminals = old_net.each_terminal().collect_vec();
for terminal in terminals {
match terminal {
TerminalRef::Pin(p) => { p.connect_net(Some(new_net.clone())); }
TerminalRef::PinInstance(p) => { p.connect_net(Some(new_net.clone())); }
}
}
self.remove_net(old_net);
}
pub fn remove_circuit_instance(&self, circuit_instance: &Rc<CircuitInstance>) -> () {
assert!(circuit_instance.parent_circuit().ptr_eq(&self.self_reference()),
"Circuit instance does not live in this circuit.");
{
let mut dependencies = self.dependencies.borrow_mut();
let (_, count) = dependencies.entry(circuit_instance.circuit_id())
.or_insert((Weak::new(), 0));
*count -= 1;
if *count == 0 {
dependencies.remove(&circuit_instance.circuit_id());
}
}
{
let circuit_ref = circuit_instance.circuit_ref().upgrade().unwrap();
let mut dependent = circuit_ref.dependent_circuits.borrow_mut();
let (_, count) = dependent.entry(self.id())
.or_insert((Weak::new(), 0));
*count -= 1;
if *count == 0 {
dependent.remove(&self.id());
}
}
for i in 0..circuit_instance.pin_count() {
circuit_instance.disconnect_pin_by_id(i);
}
if let Some(name) = circuit_instance.name() {
self.circuit_instances_by_name.borrow_mut().remove(name.as_str());
}
self.circuit_instances.borrow_mut().remove(&circuit_instance.id())
.unwrap();
let remove_successful = circuit_instance.circuit_ref().upgrade().unwrap()
.circuit_references.borrow_mut()
.remove(circuit_instance);
assert!(remove_successful, "Failed to remove circuit instance from 'circuit_references'.");
#[cfg(debug_assertions)]
{
debug_assert_eq!(self.num_references(), self.dependent_circuits.borrow().values()
.map(|(_, n)| n).sum());
let instance_ref = circuit_instance.circuit_ref().upgrade().unwrap();
debug_assert_eq!(instance_ref.num_references(), instance_ref.dependent_circuits.borrow().values()
.map(|(_, n)| n).sum());
}
}
fn self_reference(&self) -> Weak<Self> {
self.self_reference.borrow().clone()
}
pub fn circuit_instance_by_id(&self, id: &CircuitInstIndex) -> Option<Rc<CircuitInstance>> {
self.circuit_instances.borrow().get(id)
.cloned()
}
pub fn circuit_instance_by_name<S: ?Sized>(&self, name: &S) -> Option<Rc<CircuitInstance>>
where String: Borrow<S>,
S: Hash + Eq {
self.circuit_instances_by_name.borrow().get(name)
.and_then(|i| self.circuit_instance_by_id(i))
}
}