use crate::{
attribute::{Attribute, AttributeKey, AttributeValue, Parameter},
circuit::{Identifier, Instantiable, Net, Object},
error::Error,
graph::{Analysis, FanOutTable},
logic::Logic,
};
use std::{
cell::{Ref, RefCell, RefMut},
collections::{BTreeSet, HashMap, HashSet},
num::ParseIntError,
rc::{Rc, Weak},
};
trait WeakIndex<Idx: ?Sized> {
type Output: ?Sized;
fn index_weak(&self, index: &Idx) -> Rc<RefCell<Self::Output>>;
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
pub struct Gate {
name: Identifier,
inputs: Vec<Net>,
outputs: Vec<Net>,
}
impl Instantiable for Gate {
fn get_name(&self) -> &Identifier {
&self.name
}
fn get_input_ports(&self) -> impl IntoIterator<Item = &Net> {
&self.inputs
}
fn get_output_ports(&self) -> impl IntoIterator<Item = &Net> {
&self.outputs
}
fn has_parameter(&self, _id: &Identifier) -> bool {
false
}
fn get_parameter(&self, _id: &Identifier) -> Option<Parameter> {
None
}
fn set_parameter(&mut self, _id: &Identifier, _val: Parameter) -> Option<Parameter> {
None
}
fn parameters(&self) -> impl Iterator<Item = (Identifier, Parameter)> {
std::iter::empty()
}
fn from_constant(val: Logic) -> Option<Self> {
match val {
Logic::True => Some(Gate::new_logical("VDD".into(), vec![], "Y".into())),
Logic::False => Some(Gate::new_logical("GND".into(), vec![], "Y".into())),
_ => None,
}
}
fn get_constant(&self) -> Option<Logic> {
match self.name.to_string().as_str() {
"VDD" => Some(Logic::True),
"GND" => Some(Logic::False),
_ => None,
}
}
fn is_seq(&self) -> bool {
false
}
}
impl Gate {
pub fn new_logical(name: Identifier, inputs: Vec<Identifier>, output: Identifier) -> Self {
if name.is_sliced() {
panic!("Attempted to create a gate with a sliced identifier: {name}");
}
let outputs = vec![Net::new_logic(output)];
let inputs = inputs.into_iter().map(Net::new_logic).collect::<Vec<_>>();
Self {
name,
inputs,
outputs,
}
}
pub fn new_logical_multi(
name: Identifier,
inputs: Vec<Identifier>,
outputs: Vec<Identifier>,
) -> Self {
if name.is_sliced() {
panic!("Attempted to create a gate with a sliced identifier: {name}");
}
let outputs = outputs.into_iter().map(Net::new_logic).collect::<Vec<_>>();
let inputs = inputs.into_iter().map(Net::new_logic).collect::<Vec<_>>();
Self {
name,
inputs,
outputs,
}
}
pub fn get_single_output_port(&self) -> &Net {
if self.outputs.len() > 1 {
panic!("Attempted to grab output port of a multi-output gate");
}
self.outputs
.first()
.expect("Gate is missing an output port")
}
pub fn set_gate_name(&mut self, new_name: Identifier) {
self.name = new_name;
}
pub fn get_gate_name(&self) -> &Identifier {
&self.name
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
enum Operand {
DirectIndex(usize),
CellIndex(usize, usize),
}
impl Operand {
fn remap(self, x: usize) -> Self {
match self {
Operand::DirectIndex(_idx) => Operand::DirectIndex(x),
Operand::CellIndex(_idx, j) => Operand::CellIndex(x, j),
}
}
fn root(&self) -> usize {
match self {
Operand::DirectIndex(idx) => *idx,
Operand::CellIndex(idx, _) => *idx,
}
}
fn secondary(&self) -> usize {
match self {
Operand::DirectIndex(_) => 0,
Operand::CellIndex(_, j) => *j,
}
}
}
impl std::fmt::Display for Operand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Operand::DirectIndex(idx) => write!(f, "{idx}"),
Operand::CellIndex(idx, j) => write!(f, "{idx}.{j}"),
}
}
}
impl std::str::FromStr for Operand {
type Err = ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.split_once('.') {
Some((idx, j)) => {
let idx = idx.parse::<usize>()?;
let j = j.parse::<usize>()?;
Ok(Operand::CellIndex(idx, j))
}
None => {
let idx = s.parse::<usize>()?;
Ok(Operand::DirectIndex(idx))
}
}
}
}
#[derive(Debug)]
struct OwnedObject<I, O>
where
I: Instantiable,
O: WeakIndex<usize, Output = Self>,
{
object: Object<I>,
owner: Weak<O>,
operands: Vec<Option<Operand>>,
attributes: HashMap<AttributeKey, AttributeValue>,
index: usize,
}
impl<I, O> OwnedObject<I, O>
where
I: Instantiable,
O: WeakIndex<usize, Output = Self>,
{
fn inds_mut(&mut self) -> impl Iterator<Item = &mut Operand> {
self.operands
.iter_mut()
.filter_map(|operand| operand.as_mut())
}
fn get_driver(&self, index: usize) -> Option<Rc<RefCell<Self>>> {
self.operands[index].as_ref().map(|operand| {
self.owner
.upgrade()
.expect("Object is unlinked from netlist")
.index_weak(&operand.root())
})
}
fn drivers(&self) -> impl Iterator<Item = Option<Rc<RefCell<Self>>>> {
self.operands.iter().map(|operand| {
operand.as_ref().map(|operand| {
self.owner
.upgrade()
.expect("Object is unlinked from netlist")
.index_weak(&operand.root())
})
})
}
fn driver_nets(&self) -> impl Iterator<Item = Option<Net>> {
self.operands.iter().map(|operand| {
operand.as_ref().map(|operand| match operand {
Operand::DirectIndex(idx) => self
.owner
.upgrade()
.expect("Object is unlinked from netlist")
.index_weak(idx)
.borrow()
.as_net()
.clone(),
Operand::CellIndex(idx, j) => self
.owner
.upgrade()
.expect("Object is unlinked from netlist")
.index_weak(idx)
.borrow()
.get_net(*j)
.clone(),
})
})
}
fn get(&self) -> &Object<I> {
&self.object
}
fn get_mut(&mut self) -> &mut Object<I> {
&mut self.object
}
fn get_index(&self) -> usize {
self.index
}
fn as_net(&self) -> &Net {
match &self.object {
Object::Input(net) => net,
Object::Instance(nets, _, _) => {
if nets.len() > 1 {
panic!("Attempt to grab the net of a multi-output instance");
} else {
nets.first().expect("Instance is missing a net to drive")
}
}
}
}
fn as_net_mut(&mut self) -> &mut Net {
match &mut self.object {
Object::Input(net) => net,
Object::Instance(nets, _, _) => {
if nets.len() > 1 {
panic!("Attempt to grab the net of a multi-output instance");
} else {
nets.first_mut()
.expect("Instance is missing a net to drive")
}
}
}
}
fn get_net(&self, idx: usize) -> &Net {
match &self.object {
Object::Input(net) => {
if idx != 0 {
panic!("Nonzero index on an input object");
}
net
}
Object::Instance(nets, _, _) => &nets[idx],
}
}
fn get_net_mut(&mut self, idx: usize) -> &mut Net {
match &mut self.object {
Object::Input(net) => {
if idx != 0 {
panic!("Nonzero index on an input object");
}
net
}
Object::Instance(nets, _, _) => &mut nets[idx],
}
}
fn find_net(&self, net: &Net) -> Option<usize> {
match &self.object {
Object::Input(input_net) => {
if input_net == net {
Some(0)
} else {
None
}
}
Object::Instance(nets, _, _) => nets.iter().position(|n| n == net),
}
}
fn find_net_mut(&mut self, net: &Net) -> Option<&mut Net> {
match &mut self.object {
Object::Input(input_net) => {
if input_net == net {
Some(input_net)
} else {
None
}
}
Object::Instance(nets, _, _) => nets.iter_mut().find(|n| *n == net),
}
}
fn get_driver_net(&self, index: usize) -> Option<Net> {
let operand = &self.operands[index];
match operand {
Some(op) => match op {
Operand::DirectIndex(idx) => self
.owner
.upgrade()
.expect("Object is unlinked from netlist")
.index_weak(idx)
.borrow()
.as_net()
.clone()
.into(),
Operand::CellIndex(idx, j) => self
.owner
.upgrade()
.expect("Object is unlinked from netlist")
.index_weak(idx)
.borrow()
.get_net(*j)
.clone()
.into(),
},
None => None,
}
}
fn clear_attribute(&mut self, k: &AttributeKey) -> Option<AttributeValue> {
self.attributes.remove(k)
}
fn set_attribute(&mut self, k: AttributeKey) {
self.attributes.insert(k, None);
}
fn insert_attribute(&mut self, k: AttributeKey, v: String) -> Option<AttributeValue> {
self.attributes.insert(k, Some(v))
}
fn attributes(&self) -> impl Iterator<Item = Attribute> {
Attribute::from_pairs(self.attributes.clone().into_iter())
}
}
type NetRefT<I> = Rc<RefCell<OwnedObject<I, Netlist<I>>>>;
#[derive(Clone)]
pub struct NetRef<I>
where
I: Instantiable,
{
netref: NetRefT<I>,
}
impl<I> std::fmt::Debug for NetRef<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let b = self.netref.borrow();
let o = b.get();
let i = b.index;
let owner = &b.owner;
match owner.upgrade() {
Some(owner) => {
let n = owner.get_name();
write!(f, "{{ owner: \"{n}\", index: {i}, val: \"{o}\" }}")
}
None => write!(f, "{{ owner: None, index: {i}, val: \"{o}\" }}"),
}
}
}
impl<I> PartialEq for NetRef<I>
where
I: Instantiable,
{
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.netref, &other.netref)
}
}
impl<I> Eq for NetRef<I> where I: Instantiable {}
impl<I> Ord for NetRef<I>
where
I: Instantiable,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
Rc::as_ptr(&self.netref).cmp(&Rc::as_ptr(&other.netref))
}
}
impl<I> PartialOrd for NetRef<I>
where
I: Instantiable,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<I> std::hash::Hash for NetRef<I>
where
I: Instantiable,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
Rc::as_ptr(&self.netref).hash(state);
}
}
impl<I> NetRef<I>
where
I: Instantiable,
{
fn wrap(netref: NetRefT<I>) -> Self {
Self { netref }
}
fn unwrap(self) -> NetRefT<I> {
self.netref
}
pub fn as_net(&self) -> Ref<'_, Net> {
Ref::map(self.netref.borrow(), |f| f.as_net())
}
pub fn as_net_mut(&self) -> RefMut<'_, Net> {
RefMut::map(self.netref.borrow_mut(), |f| f.as_net_mut())
}
pub fn get_net(&self, idx: usize) -> Ref<'_, Net> {
Ref::map(self.netref.borrow(), |f| f.get_net(idx))
}
pub fn get_net_mut(&self, idx: usize) -> RefMut<'_, Net> {
RefMut::map(self.netref.borrow_mut(), |f| f.get_net_mut(idx))
}
pub fn get_output(&self, idx: usize) -> DrivenNet<I> {
DrivenNet::new(idx, self.clone())
}
pub fn find_output(&self, id: &Identifier) -> Option<DrivenNet<I>> {
let ind = self.get_instance_type()?.find_output(id)?;
Some(self.get_output(ind))
}
pub fn get_input(&self, idx: usize) -> InputPort<I> {
if self.is_an_input() {
panic!("Principal inputs do not have inputs");
}
InputPort::new(idx, self.clone())
}
pub fn find_input(&self, id: &Identifier) -> Option<InputPort<I>> {
let ind = self.get_instance_type()?.find_input(id)?;
Some(self.get_input(ind))
}
pub fn get_identifier(&self) -> Identifier {
self.as_net().get_identifier().clone()
}
pub fn set_identifier(&self, identifier: Identifier) {
self.as_net_mut().set_identifier(identifier)
}
pub fn is_an_input(&self) -> bool {
matches!(self.netref.borrow().get(), Object::Input(_))
}
pub fn get_obj(&self) -> Ref<'_, Object<I>> {
Ref::map(self.netref.borrow(), |f| f.get())
}
pub fn get_instance_type(&self) -> Option<Ref<'_, I>> {
Ref::filter_map(self.netref.borrow(), |f| f.get().get_instance_type()).ok()
}
pub fn get_instance_type_mut(&self) -> Option<RefMut<'_, I>> {
RefMut::filter_map(self.netref.borrow_mut(), |f| {
f.get_mut().get_instance_type_mut()
})
.ok()
}
pub fn get_instance_name(&self) -> Option<Identifier> {
match self.netref.borrow().get() {
Object::Instance(_, inst_name, _) => Some(inst_name.clone()),
_ => None,
}
}
pub fn set_instance_name(&self, name: Identifier) {
match self.netref.borrow_mut().get_mut() {
Object::Instance(_, inst_name, _) => *inst_name = name,
_ => panic!("Attempted to set instance name on a non-instance object"),
}
}
pub fn expose_as_output(self) -> Result<Self, Error> {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.expose_net(self.clone().into())?;
Ok(self)
}
pub fn expose_with_name(self, name: Identifier) -> Self {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.expose_net_with_name(self.clone().into(), name);
self
}
pub fn expose_net(&self, net: &Net) -> Result<(), Error> {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
let net_index = self
.netref
.borrow()
.find_net(net)
.ok_or(Error::NetNotFound(net.clone()))?;
let dr = DrivenNet::new(net_index, self.clone());
netlist.expose_net(dr)?;
Ok(())
}
pub fn remove_output(&self, net_name: &Identifier) -> bool {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.remove_output(&self.into(), net_name)
}
pub fn remove_all_outputs(&self) -> usize {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.remove_outputs(&self.into())
}
pub fn get_driver(&self, index: usize) -> Option<Self> {
self.netref.borrow().get_driver(index).map(NetRef::wrap)
}
pub fn get_driver_net(&self, index: usize) -> Option<Net> {
self.netref.borrow().get_driver_net(index)
}
pub fn req_driver_net(&self, index: usize) -> Option<MutBorrowReq<I>> {
let net = self.get_driver_net(index)?;
let operand = self.get_driver(index).unwrap();
Some(MutBorrowReq::new(operand, net))
}
pub fn get_num_input_ports(&self) -> usize {
if let Some(inst_type) = self.get_instance_type() {
inst_type.get_input_ports().into_iter().count()
} else {
0
}
}
pub fn is_fully_connected(&self) -> bool {
assert_eq!(
self.netref.borrow().operands.len(),
self.get_num_input_ports()
);
self.netref.borrow().operands.iter().all(|o| o.is_some())
}
pub fn drivers(&self) -> impl Iterator<Item = Option<Self>> {
let drivers: Vec<Option<Self>> = self
.netref
.borrow()
.drivers()
.map(|o| o.map(NetRef::wrap))
.collect();
drivers.into_iter()
}
pub fn driver_nets(&self) -> impl Iterator<Item = Option<Net>> {
let vec: Vec<Option<Net>> = self.netref.borrow().driver_nets().collect();
vec.into_iter()
}
#[allow(clippy::unnecessary_to_owned)]
pub fn nets(&self) -> impl Iterator<Item = Net> {
self.netref.borrow().get().get_nets().to_vec().into_iter()
}
pub fn inputs(&self) -> impl Iterator<Item = InputPort<I>> {
let len = self.netref.borrow().operands.len();
(0..len).map(move |i| InputPort::new(i, self.clone()))
}
pub fn outputs(&self) -> impl Iterator<Item = DrivenNet<I>> {
let len = self.netref.borrow().get().get_nets().len();
(0..len).map(move |i| DrivenNet::new(i, self.clone()))
}
pub fn nets_mut(&self) -> impl Iterator<Item = RefMut<'_, Net>> {
let nnets = self.netref.borrow().get().get_nets().len();
(0..nnets).map(|i| self.get_net_mut(i))
}
pub fn drives_net(&self, net: &Net) -> bool {
self.netref.borrow().find_net(net).is_some()
}
pub fn drives_a_top_output(&self) -> bool {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.drives_an_output(self.clone())
}
pub fn find_net_mut(&self, net: &Net) -> Option<RefMut<'_, Net>> {
RefMut::filter_map(self.netref.borrow_mut(), |f| f.find_net_mut(net)).ok()
}
pub fn is_multi_output(&self) -> bool {
self.netref.borrow().get().get_nets().len() > 1
}
pub fn delete_uses(self) -> Result<Object<I>, Error> {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.delete_net_uses(self)
}
pub fn replace_uses_with(self, other: &DrivenNet<I>) -> Result<NetRef<I>, Error> {
let netlist = self
.netref
.borrow()
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist
.replace_net_uses(self.into(), other)
.map(|d| d.unwrap())
}
pub fn clear_attribute(&self, k: &AttributeKey) -> Option<AttributeValue> {
self.netref.borrow_mut().clear_attribute(k)
}
pub fn set_attribute(&self, k: AttributeKey) {
self.netref.borrow_mut().set_attribute(k);
}
pub fn insert_attribute(&self, k: AttributeKey, v: String) -> Option<AttributeValue> {
self.netref.borrow_mut().insert_attribute(k, v)
}
pub fn attributes(&self) -> impl Iterator<Item = Attribute> {
let v: Vec<_> = self.netref.borrow().attributes().collect();
v.into_iter()
}
}
impl<I> std::fmt::Display for NetRef<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.netref.borrow().object.fmt(f)
}
}
impl<I> From<NetRef<I>> for DrivenNet<I>
where
I: Instantiable,
{
fn from(val: NetRef<I>) -> Self {
if val.is_multi_output() {
panic!("Cannot convert a multi-output netref to an output port");
}
DrivenNet::new(0, val)
}
}
impl<I> From<&NetRef<I>> for DrivenNet<I>
where
I: Instantiable,
{
fn from(val: &NetRef<I>) -> Self {
if val.is_multi_output() {
panic!("Cannot convert a multi-output netref to an output port");
}
DrivenNet::new(0, val.clone())
}
}
pub struct MutBorrowReq<I: Instantiable> {
from: NetRef<I>,
ind: Net,
}
impl<I> MutBorrowReq<I>
where
I: Instantiable,
{
fn new(from: NetRef<I>, ind: Net) -> Self {
Self { from, ind }
}
pub fn borrow_mut(&self) -> RefMut<'_, Net> {
self.from.find_net_mut(&self.ind).unwrap()
}
pub fn is_an_input(&self) -> bool {
self.from.is_an_input()
}
pub fn borrow_mut_if(&self, f: impl Fn(&NetRef<I>) -> bool) -> Option<RefMut<'_, Net>> {
if f(&self.from) {
Some(self.borrow_mut())
} else {
None
}
}
}
#[derive(Debug)]
pub struct Netlist<I>
where
I: Instantiable,
{
name: RefCell<String>,
objects: RefCell<Vec<NetRefT<I>>>,
outputs: RefCell<HashMap<Operand, BTreeSet<Net>>>,
}
#[derive(Debug, Clone)]
pub struct InputPort<I: Instantiable> {
pos: usize,
netref: NetRef<I>,
}
impl<I> InputPort<I>
where
I: Instantiable,
{
fn new(pos: usize, netref: NetRef<I>) -> Self {
if pos >= netref.clone().unwrap().borrow().operands.len() {
panic!(
"Position {} out of bounds for netref with {} input nets",
pos,
netref.unwrap().borrow().get().get_nets().len()
);
}
Self { pos, netref }
}
pub fn get_driver(&self) -> Option<DrivenNet<I>> {
if self.netref.is_an_input() {
panic!("Input port is not driven by a primitive");
}
if let Some(prev_operand) = self.netref.clone().unwrap().borrow().operands[self.pos] {
let netlist = self
.netref
.clone()
.unwrap()
.borrow()
.owner
.upgrade()
.expect("Input port is unlinked from netlist");
let driver_nr = netlist.index_weak(&prev_operand.root());
let nr = NetRef::wrap(driver_nr);
let pos = prev_operand.secondary();
Some(DrivenNet::new(pos, nr))
} else {
None
}
}
pub fn disconnect(&self) -> Option<DrivenNet<I>> {
let val = self.get_driver();
self.netref.clone().unwrap().borrow_mut().operands[self.pos] = None;
val
}
pub fn get_port(&self) -> Net {
if self.netref.is_an_input() {
panic!("Net is not driven by a primitive");
}
self.netref
.get_instance_type()
.unwrap()
.get_input_port(self.pos)
.clone()
}
pub fn connect(self, output: DrivenNet<I>) {
output.connect(self);
}
pub fn unwrap(self) -> NetRef<I> {
self.netref
}
pub fn get_input_num(&self) -> usize {
self.pos
}
}
impl<I> std::fmt::Display for InputPort<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.get_port().fmt(f)
}
}
#[derive(Debug, Clone)]
pub struct DrivenNet<I: Instantiable> {
pos: usize,
netref: NetRef<I>,
}
impl<I> DrivenNet<I>
where
I: Instantiable,
{
fn new(pos: usize, netref: NetRef<I>) -> Self {
if pos >= netref.clone().unwrap().borrow().get().get_nets().len() {
panic!(
"Position {} out of bounds for netref with {} outputted nets",
pos,
netref.unwrap().borrow().get().get_nets().len()
);
}
Self { pos, netref }
}
fn get_operand(&self) -> Operand {
if self.netref.is_multi_output() {
Operand::CellIndex(self.netref.clone().unwrap().borrow().get_index(), self.pos)
} else {
Operand::DirectIndex(self.netref.clone().unwrap().borrow().get_index())
}
}
pub fn as_net(&self) -> Ref<'_, Net> {
self.netref.get_net(self.pos)
}
pub fn as_net_mut(&self) -> RefMut<'_, Net> {
self.netref.get_net_mut(self.pos)
}
pub fn is_an_input(&self) -> bool {
self.netref.is_an_input()
}
pub fn get_port(&self) -> Net {
if self.netref.is_an_input() {
panic!("Net is not driven by a primitive");
}
self.netref
.get_instance_type()
.unwrap()
.get_output_port(self.pos)
.clone()
}
pub fn connect(&self, input: InputPort<I>) {
let operand = self.get_operand();
let index = input.netref.unwrap().borrow().get_index();
let netlist = self
.netref
.clone()
.unwrap()
.borrow()
.owner
.upgrade()
.expect("Output port is unlinked from netlist");
let obj = netlist.index_weak(&index);
obj.borrow_mut().operands[input.pos] = Some(operand);
}
pub fn is_top_level_output(&self) -> bool {
let netlist = self
.netref
.clone()
.unwrap()
.borrow()
.owner
.upgrade()
.expect("DrivenNet is unlinked from netlist");
let outputs = netlist.outputs.borrow();
outputs.contains_key(&self.get_operand())
}
pub fn unwrap(self) -> NetRef<I> {
self.netref
}
pub fn get_identifier(&self) -> Identifier {
self.as_net().get_identifier().clone()
}
pub fn expose_with_name(self, name: Identifier) -> Self {
let netlist = self
.netref
.clone()
.unwrap()
.borrow()
.owner
.upgrade()
.expect("DrivenNet is unlinked from netlist");
netlist.expose_net_with_name(self.clone(), name);
self
}
pub fn remove_output(&self, net_name: &Identifier) -> bool {
let netlist = self
.netref
.clone()
.unwrap()
.borrow()
.owner
.upgrade()
.expect("DrivenNet is unlinked from netlist");
netlist.remove_output(self, net_name)
}
pub fn remove_all_outputs(&self) -> usize {
let netlist = self
.netref
.clone()
.unwrap()
.borrow()
.owner
.upgrade()
.expect("DrivenNet is unlinked from netlist");
netlist.remove_outputs(self)
}
pub fn get_output_index(&self) -> Option<usize> {
if self.netref.is_an_input() {
None
} else {
Some(self.pos)
}
}
pub fn get_instance_type(&self) -> Option<Ref<'_, I>> {
self.netref.get_instance_type()
}
}
impl<I> std::fmt::Display for DrivenNet<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_net().fmt(f)
}
}
impl<I> PartialEq for DrivenNet<I>
where
I: Instantiable,
{
fn eq(&self, other: &Self) -> bool {
self.netref == other.netref && self.pos == other.pos
}
}
impl<I> Eq for DrivenNet<I> where I: Instantiable {}
impl<I> std::hash::Hash for DrivenNet<I>
where
I: Instantiable,
{
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.netref.hash(state);
self.pos.hash(state);
}
}
impl<I> Ord for DrivenNet<I>
where
I: Instantiable,
{
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.netref.cmp(&other.netref) {
std::cmp::Ordering::Equal => self.pos.cmp(&other.pos),
ord => ord,
}
}
}
impl<I> PartialOrd for DrivenNet<I>
where
I: Instantiable,
{
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<I> WeakIndex<usize> for Netlist<I>
where
I: Instantiable,
{
type Output = OwnedObject<I, Self>;
fn index_weak(&self, index: &usize) -> Rc<RefCell<Self::Output>> {
self.objects.borrow()[*index].clone()
}
}
impl<I> Netlist<I>
where
I: Instantiable,
{
pub fn new(name: String) -> Rc<Self> {
Rc::new(Self {
name: RefCell::new(name),
objects: RefCell::new(Vec::new()),
outputs: RefCell::new(HashMap::new()),
})
}
pub fn reclaim(self: Rc<Self>) -> Option<Self> {
Rc::try_unwrap(self).ok()
}
pub fn deep_clone(self: &Rc<Self>) -> Rc<Self> {
let dc = Rc::new(Self {
name: self.name.clone(),
objects: RefCell::new(Vec::new()),
outputs: self.outputs.clone(),
});
let objects_linked: Vec<NetRefT<I>> = self
.objects
.borrow()
.iter()
.map(|obj| {
Rc::new(RefCell::new(OwnedObject {
object: obj.borrow().object.clone(),
owner: Rc::downgrade(&dc),
operands: obj.borrow().operands.clone(),
attributes: obj.borrow().attributes.clone(),
index: obj.borrow().index,
}))
})
.collect();
*dc.objects.borrow_mut() = objects_linked;
dc
}
fn insert_object(
self: &Rc<Self>,
object: Object<I>,
operands: &[DrivenNet<I>],
) -> Result<NetRef<I>, Error> {
for operand in operands {
self.belongs(&operand.clone().unwrap());
}
let index = self.objects.borrow().len();
let weak = Rc::downgrade(self);
let operands = operands
.iter()
.map(|net| Some(net.get_operand()))
.collect::<Vec<_>>();
let owned_object = Rc::new(RefCell::new(OwnedObject {
object,
owner: weak,
operands,
attributes: HashMap::new(),
index,
}));
self.objects.borrow_mut().push(owned_object.clone());
Ok(NetRef::wrap(owned_object))
}
pub fn insert_input(self: &Rc<Self>, net: Net) -> DrivenNet<I> {
let obj = Object::Input(net);
self.insert_object(obj, &[]).unwrap().into()
}
pub fn insert_input_escaped_logic_bus(
self: &Rc<Self>,
net: String,
bw: usize,
) -> Vec<DrivenNet<I>> {
Net::new_escaped_logic_bus(net, bw)
.into_iter()
.map(|n| self.insert_input(n))
.collect()
}
pub fn insert_gate(
self: &Rc<Self>,
inst_type: I,
inst_name: Identifier,
operands: &[DrivenNet<I>],
) -> Result<NetRef<I>, Error> {
let nets = inst_type
.get_output_ports()
.into_iter()
.map(|pnet| pnet.with_name(&inst_name + pnet.get_identifier()))
.collect::<Vec<_>>();
let input_count = inst_type.get_input_ports().into_iter().count();
if operands.len() != input_count {
return Err(Error::ArgumentMismatch(input_count, operands.len()));
}
let obj = Object::Instance(nets, inst_name, inst_type);
self.insert_object(obj, operands)
}
pub fn insert_gate_disconnected(
self: &Rc<Self>,
inst_type: I,
inst_name: Identifier,
) -> NetRef<I> {
let nets = inst_type
.get_output_ports()
.into_iter()
.map(|pnet| pnet.with_name(&inst_name + pnet.get_identifier()))
.collect::<Vec<_>>();
let object = Object::Instance(nets, inst_name, inst_type);
let index = self.objects.borrow().len();
let weak = Rc::downgrade(self);
let input_count = object
.get_instance_type()
.unwrap()
.get_input_ports()
.into_iter()
.count();
let operands = vec![None; input_count];
let owned_object = Rc::new(RefCell::new(OwnedObject {
object,
owner: weak,
operands,
attributes: HashMap::new(),
index,
}));
self.objects.borrow_mut().push(owned_object.clone());
NetRef::wrap(owned_object)
}
pub fn insert_constant(
self: &Rc<Self>,
value: Logic,
inst_name: Identifier,
) -> Result<DrivenNet<I>, Error> {
let obj = I::from_constant(value).ok_or(Error::InstantiableError(format!(
"Instantiable type does not support constant value {}",
value
)))?;
Ok(self.insert_gate_disconnected(obj, inst_name).into())
}
fn belongs(&self, netref: &NetRef<I>) {
if let Some(nl) = netref.netref.borrow().owner.upgrade() {
if self.objects.borrow().len() != nl.objects.borrow().len() {
panic!("NetRef does not belong to this netlist");
}
if let Some(p) = self.objects.borrow().first()
&& let Some(np) = nl.objects.borrow().first()
&& !Rc::ptr_eq(p, np)
{
panic!("NetRef does not belong to this netlist");
}
}
if netref.netref.borrow().index >= self.objects.borrow().len() {
panic!("NetRef does not belong to this netlist");
}
}
pub fn get_driver(&self, netref: NetRef<I>, index: usize) -> Option<NetRef<I>> {
self.belongs(&netref);
let op = netref.unwrap().borrow().operands[index]?;
Some(NetRef::wrap(self.index_weak(&op.root()).clone()))
}
pub fn expose_net_with_name(&self, net: DrivenNet<I>, name: Identifier) -> DrivenNet<I> {
self.belongs(&net.clone().unwrap());
let mut outputs = self.outputs.borrow_mut();
let named_net = net.as_net().with_name(name);
outputs
.entry(net.get_operand())
.or_default()
.insert(named_net);
net
}
pub fn expose_net(&self, net: DrivenNet<I>) -> Result<DrivenNet<I>, Error> {
self.belongs(&net.clone().unwrap());
if net.is_an_input() {
return Err(Error::InputNeedsAlias(net.as_net().clone()));
}
let mut outputs = self.outputs.borrow_mut();
outputs
.entry(net.get_operand())
.or_default()
.insert(net.as_net().clone());
Ok(net)
}
pub fn remove_output(&self, operand: &DrivenNet<I>, net_name: &Identifier) -> bool {
self.belongs(&operand.clone().unwrap());
let mut outputs = self.outputs.borrow_mut();
if let Some(nets) = outputs.get_mut(&operand.get_operand()) {
let net_to_remove = Net::new(net_name.clone(), crate::circuit::DataType::logic());
if nets.remove(&net_to_remove) {
if nets.is_empty() {
outputs.remove(&operand.get_operand());
}
return true;
}
}
false
}
pub fn remove_outputs(&self, operand: &DrivenNet<I>) -> usize {
self.outputs
.borrow_mut()
.remove(&operand.get_operand())
.map(|nets| nets.len())
.unwrap_or(0)
}
pub fn clear_outputs(&self) {
self.outputs.borrow_mut().clear();
}
pub fn delete_net_uses(&self, netref: NetRef<I>) -> Result<Object<I>, Error> {
self.belongs(&netref);
let unwrapped = netref.clone().unwrap();
if Rc::strong_count(&unwrapped) > 3 {
return Err(Error::DanglingReference(netref.nets().collect()));
}
let old_index = unwrapped.borrow().get_index();
let objects = self.objects.borrow();
for oref in objects.iter() {
let operands = &mut oref.borrow_mut().operands;
for operand in operands.iter_mut() {
if let Some(op) = operand {
match op {
Operand::DirectIndex(idx) | Operand::CellIndex(idx, _)
if *idx == old_index =>
{
*operand = None;
}
_ => (),
}
}
}
}
let outputs: Vec<Operand> = self
.outputs
.borrow()
.keys()
.filter(|operand| match operand {
Operand::DirectIndex(idx) | Operand::CellIndex(idx, _) => *idx == old_index,
})
.cloned()
.collect();
for operand in outputs {
self.outputs.borrow_mut().remove(&operand);
}
Ok(netref.unwrap().borrow().get().clone())
}
pub fn replace_net_uses(
&self,
of: DrivenNet<I>,
with: &DrivenNet<I>,
) -> Result<DrivenNet<I>, Error> {
{
self.belongs(&of.clone().unwrap());
self.belongs(&with.clone().unwrap());
}
let unwrapped = of.clone().unwrap().unwrap();
let i = of.get_output_index();
let k = with.get_output_index();
if of.clone().unwrap() == with.clone().unwrap() {
if i == k {
return Ok(of);
}
if Rc::strong_count(&unwrapped) > 4 {
return Err(Error::DanglingReference(of.unwrap().nets().collect()));
}
} else if Rc::strong_count(&unwrapped) > 3 {
return Err(Error::DanglingReference(of.unwrap().nets().collect()));
}
let old_index = of.get_operand();
if let Some(nets) = self.outputs.borrow().get(&old_index)
&& nets.contains(&of.as_net())
{
if of.is_an_input() {
return Err(Error::NonuniqueNets(nets.iter().cloned().collect()));
} else {
let id = of.as_net().get_identifier().clone() + "_replaced".into();
of.as_net_mut().set_identifier(id);
}
}
let new_index = with.get_operand();
let objects = self.objects.borrow();
for oref in objects.iter() {
let operands = &mut oref.borrow_mut().operands;
for operand in operands.iter_mut() {
if let Some(op) = operand
&& *op == old_index
{
*operand = Some(new_index);
}
}
}
let outs = self.outputs.borrow_mut().remove(&old_index);
if let Some(outs) = outs {
self.outputs
.borrow_mut()
.entry(new_index)
.or_default()
.extend(outs);
}
Ok(of)
}
}
impl<I> Netlist<I>
where
I: Instantiable,
{
pub fn get_name(&self) -> Ref<'_, String> {
self.name.borrow()
}
pub fn set_name(&self, name: String) {
*self.name.borrow_mut() = name;
}
pub fn get_input_ports(&self) -> impl Iterator<Item = Net> {
self.objects().filter_map(|oref| {
if oref.is_an_input() {
Some(oref.as_net().clone())
} else {
None
}
})
}
pub fn get_output_ports(&self) -> Vec<Net> {
self.outputs
.borrow()
.values()
.flat_map(|nets| nets.iter().cloned())
.collect()
}
pub fn get_analysis<'a, A: Analysis<'a, I>>(&'a self) -> Result<A, Error> {
A::build(self)
}
pub fn find_net(&self, net: &Net) -> Option<DrivenNet<I>> {
for obj in self.objects() {
for o in obj.outputs() {
if *o.as_net() == *net {
return Some(o);
}
}
}
None
}
pub fn first(&self) -> Option<NetRef<I>> {
self.objects
.borrow()
.first()
.map(|nr| NetRef::wrap(nr.clone()))
}
pub fn last(&self) -> Option<NetRef<I>> {
self.objects
.borrow()
.last()
.map(|nr| NetRef::wrap(nr.clone()))
}
pub fn len(&self) -> usize {
self.objects.borrow().len()
}
pub fn is_empty(&self) -> bool {
self.objects.borrow().is_empty()
}
pub fn drives_an_output(&self, netref: NetRef<I>) -> bool {
self.belongs(&netref);
let my_index = netref.unwrap().borrow().get_index();
for key in self.outputs.borrow().keys() {
if key.root() == my_index {
return true;
}
}
false
}
pub fn rename_nets<F: Fn(&Identifier, usize) -> Identifier>(&self, f: F) -> Result<(), Error> {
let mut i: usize = 0;
for nr in self.objects() {
if nr.is_an_input() {
continue;
}
for mut net in nr.nets_mut() {
let rename = f(net.get_identifier(), i);
net.set_identifier(rename);
i += 1;
}
}
for nr in self.objects() {
if nr.is_an_input() {
continue;
}
let rename = f(&nr.get_instance_name().unwrap(), i);
nr.set_instance_name(rename);
i += 1;
}
self.verify()
}
pub fn retain_once(&self, set: &mut HashSet<DrivenNet<I>>) -> Result<Vec<Object<I>>, Error> {
let mut dead_objs = HashSet::new();
{
let fan_out = self.get_analysis::<FanOutTable<I>>()?;
for obj in self.objects() {
let mut is_dead = true;
for net in obj.outputs() {
if fan_out.net_has_uses(&net.as_net()) {
is_dead = false;
} else {
set.remove(&net);
}
}
if is_dead && !obj.is_an_input() {
dead_objs.insert(obj.unwrap().borrow().index);
}
}
}
if dead_objs.is_empty() {
return Ok(vec![]);
}
let old_objects = self.objects.take();
for i in dead_objs.iter() {
let rc = &old_objects[*i];
if Rc::strong_count(rc) > 1 {
self.objects.replace(old_objects.clone());
return Err(Error::DanglingReference(
rc.borrow().get().get_nets().to_vec(),
));
}
}
let mut removed = Vec::new();
let mut remap: HashMap<usize, usize> = HashMap::new();
for (old_index, obj) in old_objects.into_iter().enumerate() {
if dead_objs.contains(&old_index) {
removed.push(obj.borrow().get().clone());
continue;
}
let new_index = self.objects.borrow().len();
remap.insert(old_index, new_index);
obj.borrow_mut().index = new_index;
self.objects.borrow_mut().push(obj);
}
for obj in self.objects.borrow().iter() {
for operand in obj.borrow_mut().inds_mut() {
let root = operand.root();
let root = *remap.get(&root).unwrap_or(&root);
*operand = operand.remap(root);
}
}
let pairs: Vec<_> = self.outputs.take().into_iter().collect();
for (operand, net) in pairs {
let root = operand.root();
let root = *remap.get(&root).unwrap_or(&root);
let new_operand = operand.remap(root);
self.outputs.borrow_mut().insert(new_operand, net);
}
Ok(removed)
}
pub fn clean(&self) -> Result<Vec<Object<I>>, Error> {
let mut removed = Vec::new();
let mut r = self.retain_once(&mut HashSet::new())?;
while !r.is_empty() {
removed.extend(r);
r = self.retain_once(&mut HashSet::new())?;
}
Ok(removed)
}
pub fn retain(&self, set: &mut HashSet<DrivenNet<I>>) -> Result<Vec<Object<I>>, Error> {
let mut removed = Vec::new();
let mut r = self.retain_once(set)?;
while !r.is_empty() {
removed.extend(r);
r = self.retain_once(set)?;
}
Ok(removed)
}
fn nets_insts_unique(&self) -> Result<(), Error> {
let mut nets = HashSet::new();
for net in self {
if !nets.insert(net.clone().take_identifier()) {
return Err(Error::NonuniqueNets(vec![net]));
}
}
for inst in self.objects() {
if let Some(name) = inst.get_instance_name()
&& !nets.insert(name.clone())
{
return Err(Error::NonuniqueInsts(vec![name]));
}
}
Ok(())
}
fn connections_type_check(&self) -> Result<(), Error> {
for conn in self.connections() {
let target = *conn.target().get_port().get_type();
let source = *conn.src().as_net().get_type();
if target != source {
return Err(Error::TypeError(conn.src().as_net().clone()));
}
}
Ok(())
}
pub fn verify(&self) -> Result<(), Error> {
if self.outputs.borrow().is_empty() {
return Err(Error::NoOutputs);
}
self.nets_insts_unique()?;
self.connections_type_check()?;
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct Connection<I: Instantiable> {
driver: DrivenNet<I>,
input: InputPort<I>,
}
impl<I> Connection<I>
where
I: Instantiable,
{
fn new(driver: DrivenNet<I>, input: InputPort<I>) -> Self {
Self { driver, input }
}
pub fn src(&self) -> DrivenNet<I> {
self.driver.clone()
}
pub fn net(&self) -> Net {
self.driver.as_net().clone()
}
pub fn target(&self) -> InputPort<I> {
self.input.clone()
}
}
impl<I> std::fmt::Display for Connection<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.net().fmt(f)
}
}
pub mod iter {
use super::{
Connection, DrivenNet, InputPort, Instantiable, Net, NetRef, Netlist, Operand, WeakIndex,
};
use std::collections::{HashMap, HashSet};
pub struct NetIterator<'a, I: Instantiable> {
netlist: &'a Netlist<I>,
index: usize,
subindex: usize,
}
impl<'a, I> NetIterator<'a, I>
where
I: Instantiable,
{
pub fn new(netlist: &'a Netlist<I>) -> Self {
Self {
netlist,
index: 0,
subindex: 0,
}
}
}
impl<I> Iterator for NetIterator<'_, I>
where
I: Instantiable,
{
type Item = Net;
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.netlist.objects.borrow().len() {
let objects = self.netlist.objects.borrow();
let object = objects[self.index].borrow();
if self.subindex < object.get().get_nets().len() {
let net = object.get().get_nets()[self.subindex].clone();
self.subindex += 1;
return Some(net);
}
self.subindex = 0;
self.index += 1;
}
None
}
}
pub struct ObjectIterator<'a, I: Instantiable> {
netlist: &'a Netlist<I>,
index: usize,
}
impl<'a, I> ObjectIterator<'a, I>
where
I: Instantiable,
{
pub fn new(netlist: &'a Netlist<I>) -> Self {
Self { netlist, index: 0 }
}
}
impl<I> Iterator for ObjectIterator<'_, I>
where
I: Instantiable,
{
type Item = NetRef<I>;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.netlist.objects.borrow().len() {
let objects = self.netlist.objects.borrow();
let object = &objects[self.index];
self.index += 1;
return Some(NetRef::wrap(object.clone()));
}
None
}
}
pub struct ConnectionIterator<'a, I: Instantiable> {
netlist: &'a Netlist<I>,
index: usize,
subindex: usize,
}
impl<'a, I> ConnectionIterator<'a, I>
where
I: Instantiable,
{
pub fn new(netlist: &'a Netlist<I>) -> Self {
Self {
netlist,
index: 0,
subindex: 0,
}
}
}
impl<I> Iterator for ConnectionIterator<'_, I>
where
I: Instantiable,
{
type Item = super::Connection<I>;
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.netlist.objects.borrow().len() {
let objects = self.netlist.objects.borrow();
let object = objects[self.index].borrow();
let noperands = object.operands.len();
while self.subindex < noperands {
if let Some(operand) = &object.operands[self.subindex] {
let driver = match operand {
Operand::DirectIndex(idx) => {
DrivenNet::new(0, NetRef::wrap(objects[*idx].clone()))
}
Operand::CellIndex(idx, j) => {
DrivenNet::new(*j, NetRef::wrap(objects[*idx].clone()))
}
};
let input = InputPort::new(
self.subindex,
NetRef::wrap(objects[self.index].clone()),
);
self.subindex += 1;
return Some(Connection::new(driver, input));
}
self.subindex += 1;
}
self.subindex = 0;
self.index += 1;
}
None
}
}
#[derive(Clone)]
struct Walk<T: std::hash::Hash + PartialEq + Eq + Clone> {
stack: Vec<T>,
counter: HashMap<T, usize>,
}
impl<T> Walk<T>
where
T: std::hash::Hash + PartialEq + Eq + Clone,
{
fn new() -> Self {
Self {
stack: Vec::new(),
counter: HashMap::new(),
}
}
fn push(&mut self, item: T) {
self.stack.push(item.clone());
*self.counter.entry(item).or_insert(0) += 1;
}
fn contains_cycle(&self) -> bool {
self.counter.values().any(|&count| count > 1)
}
fn root_cycle(&self) -> bool {
if self.stack.is_empty() {
return false;
}
self.counter[&self.stack[0]] > 1
}
fn last(&self) -> Option<&T> {
self.stack.last()
}
}
pub struct DFSIterator<'a, I: Instantiable> {
dfs: NetDFSIterator<'a, I>,
seen: HashSet<NetRef<I>>,
}
impl<'a, I> DFSIterator<'a, I>
where
I: Instantiable,
{
pub fn new(netlist: &'a Netlist<I>, from: NetRef<I>) -> Self {
Self {
dfs: NetDFSIterator::new(netlist, DrivenNet::new(0, from)),
seen: HashSet::new(),
}
}
}
impl<I> DFSIterator<'_, I>
where
I: Instantiable,
{
pub fn check_cycles(&self) -> bool {
self.dfs.check_cycles()
}
pub fn detect_cycles(self) -> bool {
self.dfs.detect_cycles()
}
pub fn check_self_loop(&self) -> bool {
self.dfs.check_self_loop()
}
pub fn detect_self_loop(self) -> bool {
self.dfs.detect_self_loop()
}
}
impl<I> Iterator for DFSIterator<'_, I>
where
I: Instantiable,
{
type Item = NetRef<I>;
fn next(&mut self) -> Option<Self::Item> {
let d = self.dfs.next()?;
if self.seen.insert(d.clone().unwrap()) {
Some(d.unwrap())
} else {
self.next()
}
}
}
type TermFn<I> = Box<dyn Fn(&DrivenNet<I>) -> bool + 'static>;
pub struct NetDFSIterator<'a, I: Instantiable> {
netlist: &'a Netlist<I>,
stacks: Vec<Walk<DrivenNet<I>>>,
visited: HashSet<usize>,
visited_net: HashSet<(usize, usize)>,
any_cycle: bool,
root_cycle: bool,
terminate: TermFn<I>,
}
impl<'a, I> NetDFSIterator<'a, I>
where
I: Instantiable,
{
pub fn new_filtered<F: Fn(&DrivenNet<I>) -> bool + 'static>(
netlist: &'a Netlist<I>,
from: DrivenNet<I>,
terminate: F,
) -> Self {
let mut s = Walk::new();
s.push(from);
Self {
netlist,
stacks: vec![s],
visited: HashSet::new(),
visited_net: HashSet::new(),
any_cycle: false,
root_cycle: false,
terminate: Box::new(terminate),
}
}
pub fn new(netlist: &'a Netlist<I>, from: DrivenNet<I>) -> Self {
Self::new_filtered(netlist, from, |_| false)
}
}
impl<I> NetDFSIterator<'_, I>
where
I: Instantiable,
{
pub fn check_cycles(&self) -> bool {
self.any_cycle
}
pub fn detect_cycles(mut self) -> bool {
if self.any_cycle {
return true;
}
while let Some(_) = self.next() {
if self.any_cycle {
return true;
}
}
self.any_cycle
}
pub fn check_self_loop(&self) -> bool {
self.root_cycle
}
pub fn detect_self_loop(mut self) -> bool {
if self.root_cycle {
return true;
}
while let Some(_) = self.next() {
if self.root_cycle {
return true;
}
}
self.root_cycle
}
}
impl<I> Iterator for NetDFSIterator<'_, I>
where
I: Instantiable,
{
type Item = DrivenNet<I>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(walk) = self.stacks.pop() {
self.any_cycle |= walk.contains_cycle();
self.root_cycle |= walk.root_cycle();
let item = walk.last().cloned();
let uw = item.clone().unwrap().unwrap().unwrap();
let index = uw.borrow().get_index();
let secondary = item.as_ref().unwrap().pos;
if self.visited.insert(index) {
if !(self.terminate)(item.as_ref().unwrap()) {
let operands = &uw.borrow().operands;
for operand in operands.iter().flatten() {
let mut new_walk = walk.clone();
new_walk.push(DrivenNet::new(
operand.secondary(),
NetRef::wrap(self.netlist.index_weak(&operand.root())),
));
self.stacks.push(new_walk);
}
}
self.visited_net.insert((index, secondary));
return item;
}
if self.visited_net.insert((index, secondary)) {
return item;
}
return self.next();
}
None
}
}
}
impl<'a, I> IntoIterator for &'a Netlist<I>
where
I: Instantiable,
{
type Item = Net;
type IntoIter = iter::NetIterator<'a, I>;
fn into_iter(self) -> Self::IntoIter {
iter::NetIterator::new(self)
}
}
#[macro_export]
macro_rules! filter_nodes {
($netlist:ident, $pattern:pat $(if $guard:expr)? $(,)?) => {
$netlist.matches(|f| match f {
$pattern $(if $guard)? => true,
_ => false
})
};
}
impl<I> Netlist<I>
where
I: Instantiable,
{
pub fn objects(&self) -> impl Iterator<Item = NetRef<I>> {
iter::ObjectIterator::new(self)
}
pub fn matches<F>(&self, filter: F) -> impl Iterator<Item = NetRef<I>>
where
F: Fn(&I) -> bool,
{
self.objects().filter(move |f| {
if let Some(inst_type) = f.get_instance_type() {
filter(&inst_type)
} else {
false
}
})
}
pub fn inputs(&self) -> impl Iterator<Item = DrivenNet<I>> {
self.objects()
.filter(|n| n.is_an_input())
.map(|n| DrivenNet::new(0, n))
}
pub fn outputs(&self) -> Vec<(DrivenNet<I>, Net)> {
self.outputs
.borrow()
.iter()
.flat_map(|(k, nets)| {
nets.iter().map(|n| {
(
DrivenNet::new(k.secondary(), NetRef::wrap(self.index_weak(&k.root()))),
n.clone(),
)
})
})
.collect()
}
pub fn connections(&self) -> impl Iterator<Item = Connection<I>> {
iter::ConnectionIterator::new(self)
}
pub fn node_dfs(&self, from: NetRef<I>) -> impl Iterator<Item = NetRef<I>> {
self.belongs(&from);
iter::DFSIterator::new(self, from)
}
pub fn net_dfs(&self, from: DrivenNet<I>) -> impl Iterator<Item = DrivenNet<I>> {
self.belongs(&from.clone().unwrap());
iter::NetDFSIterator::new(self, from)
}
#[cfg(feature = "serde")]
pub fn serialize(self, writer: impl std::io::Write) -> Result<(), serde_json::Error>
where
I: ::serde::Serialize,
{
serde::netlist_serialize(self, writer)
}
#[cfg(feature = "graph")]
pub fn dot_string(&self) -> Result<String, Error> {
use super::graph::{Edge, MultiDiGraph, Node};
use petgraph::dot::{Config, Dot};
use petgraph::graph::{DiGraph, EdgeReference, NodeIndex};
let analysis = self.get_analysis::<MultiDiGraph<_>>()?;
let graph = analysis.get_graph();
fn node_impl<I: Instantiable>(
_graph: &DiGraph<Node<I, String>, Edge<I, Net>>,
node: (NodeIndex, &Node<I, String>),
) -> String {
let n = node.1;
let mut attr = String::new();
match n {
Node::NetRef(nr) if nr.get_instance_type().is_some() => attr += "shape=record, ",
_ => attr += "shape=ellipse, ",
}
match n {
Node::NetRef(nr)
if let Some(inst_type) = nr.get_instance_type()
&& !inst_type.is_driverless() =>
{
let mut record = "{ { ".to_string();
let l = nr.get_num_input_ports();
for (i, port) in nr.inputs().enumerate() {
let id = port.get_port().get_identifier().clone();
record += &format!("{{ <{}> {} }}", id, id);
if i != l - 1 {
record += " | ";
}
}
record += &format!(
" }} | {}({}) }}",
inst_type.get_name(),
nr.get_instance_name().unwrap()
);
attr += &format!("label=\"{record}\"");
}
_ => attr += &format!("label=\"{n}\""),
}
attr
}
fn edge_impl<I: Instantiable>(
_graph: &DiGraph<Node<I, String>, Edge<I, Net>>,
edge: EdgeReference<Edge<I, Net>>,
) -> String {
match edge.weight() {
Edge::Connection(c) => {
format!(", port=\"{}\"", c.target().get_port().get_identifier())
}
_ => String::new(),
}
}
let dot = Dot::with_attr_getters(
graph,
&[Config::NodeNoLabel],
&edge_impl::<I>,
&node_impl::<I>,
);
let mut result = String::new();
for line in dot.to_string().lines() {
if line.contains("->") && line.contains("port=") {
let port = line
.split("port=\"")
.nth(1)
.unwrap()
.split('"')
.next()
.unwrap();
let (l, r) = line.split_once("->").unwrap();
let (l, r) = (l, r.trim());
let (d, r) = r.split_once(" ").unwrap();
result += &format!("{l}-> {d}:{port} {r}\n");
} else {
result += line;
result += "\n";
}
}
Ok(result)
}
#[cfg(feature = "graph")]
pub fn dump_dot(&self) -> std::io::Result<()> {
use std::io::Write;
let mut dir = std::env::current_dir()?;
let mod_name = format!("{}.dot", self.get_name());
dir.push(mod_name);
let mut file = std::fs::File::create(dir)?;
if let Err(e) = self.verify() {
write!(file, "Netlist verification failed: {e}")
} else {
let dot = self.dot_string().unwrap();
write!(file, "{dot}")
}
}
}
impl<I> std::fmt::Display for Netlist<I>
where
I: Instantiable,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let objects = self.objects.borrow();
let outputs = self.outputs.borrow();
writeln!(f, "module {} (", self.get_name())?;
let level = 2;
let indent = " ".repeat(level);
for oref in objects.iter() {
let owned = oref.borrow();
let obj = owned.get();
if let Object::Input(net) = obj {
writeln!(f, "{}{},", indent, net.get_identifier().emit_name())?;
}
}
let all_outputs: Vec<_> = outputs.values().flat_map(|nets| nets.iter()).collect();
for (i, net) in all_outputs.iter().enumerate() {
if i == all_outputs.len() - 1 {
writeln!(f, "{}{}", indent, net.get_identifier().emit_name())?;
} else {
writeln!(f, "{}{},", indent, net.get_identifier().emit_name())?;
}
}
writeln!(f, ");")?;
let mut already_decl = HashSet::new();
for oref in objects.iter() {
let owned = oref.borrow();
let obj = owned.get();
if let Object::Input(net) = obj {
writeln!(f, "{}input {};", indent, net.get_identifier().emit_name())?;
writeln!(f, "{}wire {};", indent, net.get_identifier().emit_name())?;
already_decl.insert(net.clone());
}
}
for nets in outputs.values() {
for net in nets {
if !already_decl.contains(net) {
writeln!(f, "{}output {};", indent, net.get_identifier().emit_name())?;
writeln!(f, "{}wire {};", indent, net.get_identifier().emit_name())?;
already_decl.insert(net.clone());
}
}
}
for oref in objects.iter() {
let owned = oref.borrow();
let obj = owned.get();
if let Object::Instance(nets, _, inst_type) = obj
&& inst_type.get_constant().is_none()
{
for net in nets.iter() {
if !already_decl.contains(net) {
writeln!(f, "{}wire {};", indent, net.get_identifier().emit_name())?;
already_decl.insert(net.clone());
}
}
}
}
for oref in objects.iter() {
let owned = oref.borrow();
let obj = owned.get();
if let Some(inst_type) = obj.get_instance_type()
&& inst_type.get_constant().is_some()
{
continue;
}
if let Object::Instance(nets, inst_name, inst_type) = obj {
for (k, v) in owned.attributes.iter() {
if let Some(value) = v {
writeln!(f, "{indent}(* {k} = \"{value}\" *)")?;
} else {
writeln!(f, "{indent}(* {k} *)")?;
}
}
write!(f, "{}{} ", indent, inst_type.get_name())?;
if inst_type.is_parameterized() {
writeln!(f, "#(")?;
let level = 4;
let indent = " ".repeat(level);
let params: Vec<_> = inst_type.parameters().collect();
for (i, (k, v)) in params.iter().enumerate() {
if i == params.len() - 1 {
writeln!(f, "{indent}.{k}({v})")?;
} else {
writeln!(f, "{indent}.{k}({v}),")?;
}
}
let level = 2;
let indent = " ".repeat(level);
write!(f, "{indent}) ")?;
}
writeln!(f, "{} (", inst_name.emit_name())?;
let level = 4;
let indent = " ".repeat(level);
for (idx, port) in inst_type.get_input_ports().into_iter().enumerate() {
let port_name = port.get_identifier().emit_name();
if let Some(operand) = owned.operands[idx].as_ref() {
let operand_net = match operand {
Operand::DirectIndex(idx) => objects[*idx].borrow().as_net().clone(),
Operand::CellIndex(idx, j) => {
objects[*idx].borrow().get_net(*j).clone()
}
};
let operand_str = if let Some(inst_type) =
objects[operand.root()].borrow().get().get_instance_type()
&& let Some(logic) = inst_type.get_constant()
{
logic.to_string()
} else {
operand_net.get_identifier().emit_name()
};
writeln!(f, "{}.{}({}),", indent, port_name, operand_str)?;
}
}
for (idx, net) in nets.iter().enumerate() {
let port_name = inst_type.get_output_port(idx).get_identifier().emit_name();
if idx == nets.len() - 1 {
writeln!(
f,
"{}.{}({})",
indent,
port_name,
net.get_identifier().emit_name()
)?;
} else {
writeln!(
f,
"{}.{}({}),",
indent,
port_name,
net.get_identifier().emit_name()
)?;
}
}
let level = 2;
let indent = " ".repeat(level);
writeln!(f, "{indent});")?;
}
}
for (driver, nets) in outputs.iter() {
for net in nets {
let driver_net = match driver {
Operand::DirectIndex(idx) => self.index_weak(idx).borrow().as_net().clone(),
Operand::CellIndex(idx, j) => self.index_weak(idx).borrow().get_net(*j).clone(),
};
let driver_str = if let Some(inst_type) = self
.index_weak(&driver.root())
.borrow()
.get()
.get_instance_type()
&& let Some(logic) = inst_type.get_constant()
{
logic.to_string()
} else {
driver_net.get_identifier().emit_name()
};
if net.get_identifier() != driver_net.get_identifier() {
writeln!(
f,
"{}assign {} = {};",
indent,
net.get_identifier().emit_name(),
driver_str
)?;
}
}
}
writeln!(f, "endmodule")
}
}
pub type GateNetlist = Netlist<Gate>;
pub type GateRef = NetRef<Gate>;
#[cfg(test)]
mod tests {
use super::iter::{DFSIterator, NetDFSIterator};
use super::*;
#[test]
fn test_delete_netlist() {
let netlist = Netlist::new("simple_example".to_string());
let input1 = netlist.insert_input("input1".into());
let input2 = netlist.insert_input("input2".into());
let instance = netlist
.insert_gate(
Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into()),
"my_and".into(),
&[input1.clone(), input2.clone()],
)
.unwrap();
let instance = instance.expose_as_output().unwrap();
instance.delete_uses().unwrap();
assert!(netlist.clean().is_ok());
input1.expose_with_name("an_output".into());
assert!(netlist.clean().is_ok());
}
#[test]
#[should_panic(expected = "Attempted to create a gate with a sliced identifier")]
fn gate_w_slice_panics() {
Gate::new_logical("AND[1]".into(), vec!["A".into(), "B".into()], "Y".into());
}
#[test]
fn gates_dont_have_params() {
let gate = Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into());
assert!(!gate.has_parameter(&"id".into()));
assert!(gate.get_parameter(&"id".into()).is_none());
assert_eq!(*gate.get_gate_name(), "AND".into());
}
#[test]
fn operand_conversions() {
let operand = Operand::CellIndex(3, 2);
assert_eq!(operand.to_string(), "3.2");
let parsed = "3.2".parse::<Operand>();
assert!(parsed.is_ok());
let parsed = parsed.unwrap();
assert_eq!(operand, parsed);
}
#[test]
#[should_panic(expected = "out of bounds for netref")]
fn test_bad_output() {
let netlist = GateNetlist::new("min_module".to_string());
let a = netlist.insert_input("a".into());
DrivenNet::new(1, a.unwrap());
}
#[test]
fn test_netdfsiterator() {
let netlist = Netlist::new("dfs_netlist".to_string());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());
let c = netlist.insert_input("c".into());
let d = netlist.insert_input("d".into());
let e = netlist.insert_input("e".into());
let n1 = netlist
.insert_gate(
Gate::new_logical("OR".into(), vec!["A".into(), "B".into()], "Y".into()),
"n1".into(),
&[a.clone(), b.clone()],
)
.unwrap()
.get_output(0);
let n2 = netlist
.insert_gate(
Gate::new_logical("NOR".into(), vec!["A".into(), "B".into()], "Y".into()),
"n2".into(),
&[d.clone(), e.clone()],
)
.unwrap()
.get_output(0);
let n3 = netlist
.insert_gate(
Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into()),
"n3".into(),
&[n1.clone(), c.clone()],
)
.unwrap()
.get_output(0);
let n4 = netlist
.insert_gate(
Gate::new_logical("NAND".into(), vec!["A".into(), "B".into()], "Y".into()),
"n4".into(),
&[n3.clone(), n2.clone()],
)
.unwrap()
.get_output(0);
n4.clone().expose_with_name("y".into());
let mut dfs = NetDFSIterator::new(&netlist, n4.clone());
assert_eq!(dfs.next(), Some(n4));
assert_eq!(dfs.next(), Some(n2));
assert_eq!(dfs.next(), Some(e));
assert_eq!(dfs.next(), Some(d));
assert_eq!(dfs.next(), Some(n3));
assert_eq!(dfs.next(), Some(c));
assert_eq!(dfs.next(), Some(n1));
assert_eq!(dfs.next(), Some(b));
assert_eq!(dfs.next(), Some(a));
assert_eq!(dfs.next(), None);
}
#[test]
fn test_dfs_cycles() {
let netlist = Netlist::new("dfs_cycles".to_string());
let a = netlist.insert_input("a".into());
let and = netlist.insert_gate_disconnected(
Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into()),
"and".into(),
);
a.connect(and.get_input(0));
and.get_output(0).connect(and.get_input(1));
let dfs = DFSIterator::new(&netlist, and.clone());
let driven_dfs = NetDFSIterator::new(&netlist, and.get_output(0));
assert!(dfs.detect_cycles());
assert!(driven_dfs.detect_cycles());
}
#[test]
fn test_netdfsiterator_with_boundary() {
let netlist = Netlist::new("dfs_netlist".to_string());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());
let c = netlist.insert_input("c".into());
let d = netlist.insert_input("d".into());
let e = netlist.insert_input("e".into());
let n1 = netlist
.insert_gate(
Gate::new_logical("OR".into(), vec!["A".into(), "B".into()], "Y".into()),
"n1".into(),
&[a.clone(), b.clone()],
)
.unwrap()
.get_output(0);
let n2 = netlist
.insert_gate(
Gate::new_logical("NOR".into(), vec!["A".into(), "B".into()], "Y".into()),
"n2".into(),
&[d.clone(), e.clone()],
)
.unwrap()
.get_output(0);
let n3 = netlist
.insert_gate(
Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into()),
"n3".into(),
&[n1.clone(), c.clone()],
)
.unwrap()
.get_output(0);
let n4 = netlist
.insert_gate(
Gate::new_logical("NAND".into(), vec!["A".into(), "B".into()], "Y".into()),
"n4".into(),
&[n3.clone(), n2.clone()],
)
.unwrap()
.get_output(0);
let n3_boundary = n3.clone();
let mut dfs =
NetDFSIterator::new_filtered(&netlist, n4.clone(), move |n| *n == n3_boundary);
assert_eq!(dfs.next(), Some(n4));
assert_eq!(dfs.next(), Some(n2));
assert_eq!(dfs.next(), Some(e));
assert_eq!(dfs.next(), Some(d));
assert_eq!(dfs.next(), Some(n3));
assert_eq!(dfs.next(), None);
}
#[test]
fn test_dfs_convergence() {
let netlist = GateNetlist::new("example".to_string());
let gate = Gate::new_logical_multi(
"FA".into(),
vec!["A".into(), "B".into()],
vec!["S".into(), "COUT".into()],
);
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());
let gate = netlist.insert_gate(gate, "g".into(), &[a, b]).unwrap();
let s = gate.get_output(0);
let c = gate.get_output(1);
let gate = Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into());
let d = netlist.insert_gate(gate, "h".into(), &[s, c]).unwrap();
let dfs = NetDFSIterator::new(&netlist, d.get_output(0));
let c = dfs.count();
assert_eq!(c, 5);
let dfs = DFSIterator::new(&netlist, d.clone());
let c = dfs.count();
assert_eq!(c, 4);
}
}
#[cfg(feature = "serde")]
pub mod serde {
use super::{Netlist, Operand, OwnedObject, WeakIndex};
use crate::{
attribute::{AttributeKey, AttributeValue},
circuit::{Instantiable, Net, Object},
};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use std::cell::RefCell;
use std::{
collections::{BTreeSet, HashMap},
rc::Rc,
};
#[derive(Debug, Serialize, Deserialize)]
struct SerdeObject<I>
where
I: Instantiable + Serialize,
{
object: Object<I>,
operands: Vec<Option<Operand>>,
attributes: HashMap<AttributeKey, AttributeValue>,
}
impl<I, O> From<OwnedObject<I, O>> for SerdeObject<I>
where
I: Instantiable + Serialize,
O: WeakIndex<usize, Output = OwnedObject<I, O>>,
{
fn from(value: OwnedObject<I, O>) -> Self {
SerdeObject {
object: value.object,
operands: value.operands,
attributes: value.attributes,
}
}
}
impl<I> SerdeObject<I>
where
I: Instantiable + Serialize,
{
fn into_owned_object<O>(self, owner: &Rc<O>, index: usize) -> OwnedObject<I, O>
where
O: WeakIndex<usize, Output = OwnedObject<I, O>>,
{
OwnedObject {
object: self.object,
owner: Rc::downgrade(owner),
operands: self.operands,
attributes: self.attributes,
index,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct SerdeNetlist<I>
where
I: Instantiable + Serialize,
{
name: String,
objects: Vec<SerdeObject<I>>,
outputs: HashMap<String, BTreeSet<Net>>,
}
impl<I> From<Netlist<I>> for SerdeNetlist<I>
where
I: Instantiable + Serialize,
{
fn from(value: Netlist<I>) -> Self {
SerdeNetlist {
name: value.name.into_inner(),
objects: value
.objects
.into_inner()
.into_iter()
.map(|o| {
Rc::try_unwrap(o)
.ok()
.expect("Cannot serialize with live references")
.into_inner()
.into()
})
.collect(),
outputs: value
.outputs
.into_inner()
.into_iter()
.map(|(o, nets)| (o.to_string(), nets.into_iter().collect()))
.collect(),
}
}
}
impl<I> SerdeNetlist<I>
where
I: Instantiable + Serialize,
{
fn into_netlist(self) -> Rc<Netlist<I>> {
let netlist = Netlist::new(self.name);
let outputs: HashMap<Operand, BTreeSet<Net>> = self
.outputs
.into_iter()
.map(|(k, v)| {
let operand = k.parse::<Operand>().expect("Invalid index");
(operand, v.into_iter().collect())
})
.collect();
let objects = self
.objects
.into_iter()
.enumerate()
.map(|(i, o)| {
let owned_object = o.into_owned_object(&netlist, i);
Rc::new(RefCell::new(owned_object))
})
.collect::<Vec<_>>();
{
let mut objs_mut = netlist.objects.borrow_mut();
*objs_mut = objects;
let mut outputs_mut = netlist.outputs.borrow_mut();
*outputs_mut = outputs;
}
netlist
}
}
pub fn netlist_serialize<I: Instantiable + Serialize>(
netlist: Netlist<I>,
writer: impl std::io::Write,
) -> Result<(), serde_json::Error> {
let sobj: SerdeNetlist<I> = netlist.into();
serde_json::to_writer_pretty(writer, &sobj)
}
pub fn netlist_deserialize<I: Instantiable + Serialize + DeserializeOwned>(
reader: impl std::io::Read,
) -> Result<Rc<Netlist<I>>, serde_json::Error> {
let sobj: SerdeNetlist<I> = serde_json::from_reader(reader)?;
Ok(sobj.into_netlist())
}
}