Skip to content

Commit 26cc201

Browse files
authored
Give netref hashes with pointer-like semantics (#6)
1 parent 578bbb1 commit 26cc201

File tree

3 files changed

+72
-37
lines changed

3 files changed

+72
-37
lines changed

src/bin/main.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,7 @@ fn main() {
100100
.unwrap();
101101
println!("Logic levels: {}", logic_levels.get_max_depth());
102102
for n in netlist.objects() {
103-
for n in n.nets() {
104-
println!(
105-
"{}: {}",
106-
n.get_identifier(),
107-
logic_levels.get_comb_depth(&n).unwrap()
108-
);
109-
}
103+
println!("{}: {}", n, logic_levels.get_comb_depth(&n).unwrap());
110104
}
111105
// let fo = netlist
112106
// .get_analysis::<circuit::graph::FanOutTable<_>>()

src/graph.rs

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,23 @@ use std::collections::hash_map::Entry;
1515
use std::collections::{HashMap, HashSet};
1616

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

2627
/// A table that maps nets to the circuit nodes they drive
2728
pub struct FanOutTable<'a, I: Instantiable> {
2829
// A reference to the underlying netlist
2930
_netlist: &'a Netlist<I>,
30-
// Maps a net to the list of nets it drives
31-
fan_out: HashMap<Net, Vec<NetRef<I>>>,
31+
// Maps a net to the list of nodes it drives
32+
net_fan_out: HashMap<Net, Vec<NetRef<I>>>,
33+
/// Maps a node to the list of nodes it drives
34+
node_fan_out: HashMap<NetRef<I>, Vec<NetRef<I>>>,
3235
/// Contains nets which are outputs
3336
is_an_output: HashSet<Net>,
3437
}
@@ -38,17 +41,25 @@ where
3841
I: Instantiable,
3942
{
4043
/// Returns an iterator to the circuit nodes that use `net`.
41-
pub fn get_users(&self, net: &Net) -> impl Iterator<Item = NetRef<I>> {
42-
self.fan_out
44+
pub fn get_net_users(&self, net: &Net) -> impl Iterator<Item = NetRef<I>> {
45+
self.net_fan_out
4346
.get(net)
4447
.into_iter()
4548
.flat_map(|users| users.iter().cloned())
4649
}
4750

51+
/// Returns an iterator to the circuit nodes that use `node`.
52+
pub fn get_node_users(&self, node: &NetRef<I>) -> impl Iterator<Item = NetRef<I>> {
53+
self.node_fan_out
54+
.get(node)
55+
.into_iter()
56+
.flat_map(|users| users.iter().cloned())
57+
}
58+
4859
/// Returns `true` if the net has any used by any cells in the circuit
4960
/// This does incude nets that are only used as outputs.
50-
pub fn has_uses(&self, net: &Net) -> bool {
51-
(self.fan_out.contains_key(net) && !self.fan_out.get(net).unwrap().is_empty())
61+
pub fn net_has_uses(&self, net: &Net) -> bool {
62+
(self.net_fan_out.contains_key(net) && !self.net_fan_out.get(net).unwrap().is_empty())
5263
|| self.is_an_output.contains(net)
5364
}
5465
}
@@ -58,14 +69,28 @@ where
5869
I: Instantiable,
5970
{
6071
fn build(netlist: &'a Netlist<I>) -> Result<Self, String> {
61-
let mut fan_out: HashMap<Net, Vec<NetRef<I>>> = HashMap::new();
72+
let mut net_fan_out: HashMap<Net, Vec<NetRef<I>>> = HashMap::new();
73+
#[allow(clippy::mutable_key_type)]
74+
let mut node_fan_out: HashMap<NetRef<I>, Vec<NetRef<I>>> = HashMap::new();
6275
let mut is_an_output: HashSet<Net> = HashSet::new();
6376

6477
for c in netlist.connections() {
65-
if let Entry::Vacant(e) = fan_out.entry(c.net()) {
78+
if let Entry::Vacant(e) = net_fan_out.entry(c.net()) {
79+
e.insert(vec![c.target().unwrap()]);
80+
} else {
81+
net_fan_out
82+
.get_mut(&c.net())
83+
.unwrap()
84+
.push(c.target().unwrap());
85+
}
86+
87+
if let Entry::Vacant(e) = node_fan_out.entry(c.src().unwrap()) {
6688
e.insert(vec![c.target().unwrap()]);
6789
} else {
68-
fan_out.get_mut(&c.net()).unwrap().push(c.target().unwrap());
90+
node_fan_out
91+
.get_mut(&c.src().unwrap())
92+
.unwrap()
93+
.push(c.target().unwrap());
6994
}
7095
}
7196

@@ -76,7 +101,8 @@ where
76101

77102
Ok(FanOutTable {
78103
_netlist: netlist,
79-
fan_out,
104+
net_fan_out,
105+
node_fan_out,
80106
is_an_output,
81107
})
82108
}
@@ -88,7 +114,7 @@ pub struct SimpleCombDepth<'a, I: Instantiable> {
88114
// A reference to the underlying netlist
89115
_netlist: &'a Netlist<I>,
90116
// Maps a net to its logic level as a DAG
91-
comb_depth: HashMap<Net, usize>,
117+
comb_depth: HashMap<NetRef<I>, usize>,
92118
/// The maximum depth of the circuit
93119
max_depth: usize,
94120
}
@@ -97,9 +123,9 @@ impl<I> SimpleCombDepth<'_, I>
97123
where
98124
I: Instantiable,
99125
{
100-
/// Returns the logic level of a net in the circuit.
101-
pub fn get_comb_depth(&self, net: &Net) -> Option<usize> {
102-
self.comb_depth.get(net).cloned()
126+
/// Returns the logic level of a node in the circuit.
127+
pub fn get_comb_depth(&self, node: &NetRef<I>) -> Option<usize> {
128+
self.comb_depth.get(node).cloned()
103129
}
104130

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

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

130157
for node in nodes {
131158
if node.is_an_input() {
132-
comb_depth.insert(node.as_net().clone(), 0);
159+
comb_depth.insert(node.clone(), 0);
133160
} else {
134161
// TODO(matth2k): get_driver_net() relies on a weak reference. Rewrite without it.
135162
let max_depth: usize = (0..node.get_num_input_ports())
136-
.filter_map(|i| netlist.get_driver_net(node.clone(), i))
163+
.filter_map(|i| netlist.get_driver(node.clone(), i))
137164
.filter_map(|n| comb_depth.get(&n))
138165
.max()
139166
.cloned()
140167
.unwrap_or(usize::MAX);
141-
for net in node.nets() {
142-
comb_depth.insert(net, max_depth + 1);
143-
}
168+
169+
comb_depth.insert(node, max_depth + 1);
144170
}
145171
}
146172

src/netlist.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,26 @@ where
376376
netref: NetRefT<I>,
377377
}
378378

379+
impl<I> PartialEq for NetRef<I>
380+
where
381+
I: Instantiable,
382+
{
383+
fn eq(&self, other: &Self) -> bool {
384+
Rc::ptr_eq(&self.netref, &other.netref)
385+
}
386+
}
387+
388+
impl<I> Eq for NetRef<I> where I: Instantiable {}
389+
390+
impl<I> std::hash::Hash for NetRef<I>
391+
where
392+
I: Instantiable,
393+
{
394+
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
395+
Rc::as_ptr(&self.netref).hash(state);
396+
}
397+
}
398+
379399
impl<I> NetRef<I>
380400
where
381401
I: Instantiable,
@@ -1104,19 +1124,14 @@ where
11041124
Ok(NetRef::wrap(owned_object))
11051125
}
11061126

1107-
/// Returns the driving net at input position `index` for `netref`
1127+
/// Returns the driving node at input position `index` for `netref`
11081128
///
11091129
/// # Panics
11101130
///
11111131
/// Panics if `index` is out of bounds
1112-
pub fn get_driver_net(&self, netref: NetRef<I>, index: usize) -> Option<Net> {
1132+
pub fn get_driver(&self, netref: NetRef<I>, index: usize) -> Option<NetRef<I>> {
11131133
let op = netref.unwrap().borrow().operands[index].clone()?;
1114-
Some(
1115-
self.index_weak(&op.root())
1116-
.borrow()
1117-
.get_net(op.secondary())
1118-
.clone(),
1119-
)
1134+
Some(NetRef::wrap(self.index_weak(&op.root()).clone()))
11201135
}
11211136

11221137
/// Set an added object as a top-level output.
@@ -1294,7 +1309,7 @@ where
12941309
let mut is_dead = true;
12951310
for net in obj.nets() {
12961311
// This should account for outputs
1297-
if fan_out.has_uses(&net) {
1312+
if fan_out.net_has_uses(&net) {
12981313
is_dead = false;
12991314
break;
13001315
}

0 commit comments

Comments
 (0)