Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,7 @@ fn main() {
.unwrap();
println!("Logic levels: {}", logic_levels.get_max_depth());
for n in netlist.objects() {
for n in n.nets() {
println!(
"{}: {}",
n.get_identifier(),
logic_levels.get_comb_depth(&n).unwrap()
);
}
println!("{}: {}", n, logic_levels.get_comb_depth(&n).unwrap());
}
// let fo = netlist
// .get_analysis::<circuit::graph::FanOutTable<_>>()
Expand Down
68 changes: 47 additions & 21 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,23 @@ use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};

/// A common trait of analyses than can be performed on a netlist.
/// An analysis becomes stale when the netlist is modified.
pub trait Analysis<'a, I: Instantiable>
where
Self: Sized + 'a,
{
/// Construct the analysis
/// Construct the analysis to the current state of the netlist.
fn build(netlist: &'a Netlist<I>) -> Result<Self, String>;
}

/// A table that maps nets to the circuit nodes they drive
pub struct FanOutTable<'a, I: Instantiable> {
// A reference to the underlying netlist
_netlist: &'a Netlist<I>,
// Maps a net to the list of nets it drives
fan_out: HashMap<Net, Vec<NetRef<I>>>,
// Maps a net to the list of nodes it drives
net_fan_out: HashMap<Net, Vec<NetRef<I>>>,
/// Maps a node to the list of nodes it drives
node_fan_out: HashMap<NetRef<I>, Vec<NetRef<I>>>,
/// Contains nets which are outputs
is_an_output: HashSet<Net>,
}
Expand All @@ -38,17 +41,25 @@ where
I: Instantiable,
{
/// Returns an iterator to the circuit nodes that use `net`.
pub fn get_users(&self, net: &Net) -> impl Iterator<Item = NetRef<I>> {
self.fan_out
pub fn get_net_users(&self, net: &Net) -> impl Iterator<Item = NetRef<I>> {
self.net_fan_out
.get(net)
.into_iter()
.flat_map(|users| users.iter().cloned())
}

/// Returns an iterator to the circuit nodes that use `node`.
pub fn get_node_users(&self, node: &NetRef<I>) -> impl Iterator<Item = NetRef<I>> {
self.node_fan_out
.get(node)
.into_iter()
.flat_map(|users| users.iter().cloned())
}

/// Returns `true` if the net has any used by any cells in the circuit
/// This does incude nets that are only used as outputs.
pub fn has_uses(&self, net: &Net) -> bool {
(self.fan_out.contains_key(net) && !self.fan_out.get(net).unwrap().is_empty())
pub fn net_has_uses(&self, net: &Net) -> bool {
(self.net_fan_out.contains_key(net) && !self.net_fan_out.get(net).unwrap().is_empty())
|| self.is_an_output.contains(net)
}
}
Expand All @@ -58,14 +69,28 @@ where
I: Instantiable,
{
fn build(netlist: &'a Netlist<I>) -> Result<Self, String> {
let mut fan_out: HashMap<Net, Vec<NetRef<I>>> = HashMap::new();
let mut net_fan_out: HashMap<Net, Vec<NetRef<I>>> = HashMap::new();
#[allow(clippy::mutable_key_type)]
let mut node_fan_out: HashMap<NetRef<I>, Vec<NetRef<I>>> = HashMap::new();
let mut is_an_output: HashSet<Net> = HashSet::new();

for c in netlist.connections() {
if let Entry::Vacant(e) = fan_out.entry(c.net()) {
if let Entry::Vacant(e) = net_fan_out.entry(c.net()) {
e.insert(vec![c.target().unwrap()]);
} else {
net_fan_out
.get_mut(&c.net())
.unwrap()
.push(c.target().unwrap());
}

if let Entry::Vacant(e) = node_fan_out.entry(c.src().unwrap()) {
e.insert(vec![c.target().unwrap()]);
} else {
fan_out.get_mut(&c.net()).unwrap().push(c.target().unwrap());
node_fan_out
.get_mut(&c.src().unwrap())
.unwrap()
.push(c.target().unwrap());
}
}

Expand All @@ -76,7 +101,8 @@ where

Ok(FanOutTable {
_netlist: netlist,
fan_out,
net_fan_out,
node_fan_out,
is_an_output,
})
}
Expand All @@ -88,7 +114,7 @@ pub struct SimpleCombDepth<'a, I: Instantiable> {
// A reference to the underlying netlist
_netlist: &'a Netlist<I>,
// Maps a net to its logic level as a DAG
comb_depth: HashMap<Net, usize>,
comb_depth: HashMap<NetRef<I>, usize>,
/// The maximum depth of the circuit
max_depth: usize,
}
Expand All @@ -97,9 +123,9 @@ impl<I> SimpleCombDepth<'_, I>
where
I: Instantiable,
{
/// Returns the logic level of a net in the circuit.
pub fn get_comb_depth(&self, net: &Net) -> Option<usize> {
self.comb_depth.get(net).cloned()
/// Returns the logic level of a node in the circuit.
pub fn get_comb_depth(&self, node: &NetRef<I>) -> Option<usize> {
self.comb_depth.get(node).cloned()
}

/// Returns the maximum logic level of the circuit.
Expand All @@ -113,7 +139,8 @@ where
I: Instantiable,
{
fn build(netlist: &'a Netlist<I>) -> Result<Self, String> {
let mut comb_depth: HashMap<Net, usize> = HashMap::new();
#[allow(clippy::mutable_key_type)]
let mut comb_depth: HashMap<NetRef<I>, usize> = HashMap::new();

let mut nodes = Vec::new();
for (driven, _) in netlist.outputs() {
Expand All @@ -129,18 +156,17 @@ where

for node in nodes {
if node.is_an_input() {
comb_depth.insert(node.as_net().clone(), 0);
comb_depth.insert(node.clone(), 0);
} else {
// TODO(matth2k): get_driver_net() relies on a weak reference. Rewrite without it.
let max_depth: usize = (0..node.get_num_input_ports())
.filter_map(|i| netlist.get_driver_net(node.clone(), i))
.filter_map(|i| netlist.get_driver(node.clone(), i))
.filter_map(|n| comb_depth.get(&n))
.max()
.cloned()
.unwrap_or(usize::MAX);
for net in node.nets() {
comb_depth.insert(net, max_depth + 1);
}

comb_depth.insert(node, max_depth + 1);
}
}

Expand Down
33 changes: 24 additions & 9 deletions src/netlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,26 @@ where
netref: NetRefT<I>,
}

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> 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,
Expand Down Expand Up @@ -1104,19 +1124,14 @@ where
Ok(NetRef::wrap(owned_object))
}

/// Returns the driving net at input position `index` for `netref`
/// Returns the driving node at input position `index` for `netref`
///
/// # Panics
///
/// Panics if `index` is out of bounds
pub fn get_driver_net(&self, netref: NetRef<I>, index: usize) -> Option<Net> {
pub fn get_driver(&self, netref: NetRef<I>, index: usize) -> Option<NetRef<I>> {
let op = netref.unwrap().borrow().operands[index].clone()?;
Some(
self.index_weak(&op.root())
.borrow()
.get_net(op.secondary())
.clone(),
)
Some(NetRef::wrap(self.index_weak(&op.root()).clone()))
}

/// Set an added object as a top-level output.
Expand Down Expand Up @@ -1294,7 +1309,7 @@ where
let mut is_dead = true;
for net in obj.nets() {
// This should account for outputs
if fan_out.has_uses(&net) {
if fan_out.net_has_uses(&net) {
is_dead = false;
break;
}
Expand Down