Skip to content
Draft
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
18 changes: 10 additions & 8 deletions src/netlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ where
.owner
.upgrade()
.expect("NetRef is unlinked from netlist");
netlist.replace_net_uses(self, other)
netlist.replace_net_uses(self.into(), &other.clone().into())
}

/// Clears the attribute with the given key on this circuit node.
Expand Down Expand Up @@ -1336,16 +1336,17 @@ where

/// Replaces the uses of a circuit node with another circuit node. The [Object] stored at `of` is returned.
/// Panics if `of` and `with` are not single-output nodes.
pub fn replace_net_uses(&self, of: NetRef<I>, with: &NetRef<I>) -> Result<Object<I>, String> {
let unwrapped = of.clone().unwrap();
pub fn replace_net_uses(&self, of: DrivenNet<I>, with: &DrivenNet<I>) -> Result<Object<I>, String> {
let unwrapped = of.clone().unwrap().unwrap();
// Rc (1) - Netlist Owner
// Rc (2) - Argument
// Rc (3) - Unwrapped Counter Checker
if Rc::strong_count(&unwrapped) > 3 {
return Err("Cannot replace. References still exist on this node".to_string());
}

let old_tag: DrivenNet<I> = of.clone().into();
let old_index = old_tag.get_operand();
let new_tag: DrivenNet<I> = with.clone().into();
let new_index = new_tag.get_operand();
let old_index = of.get_operand();
let new_index = with.get_operand();
let objects = self.objects.borrow();
for oref in objects.iter() {
let operands = &mut oref.borrow_mut().operands;
Expand All @@ -1367,8 +1368,9 @@ where
self.outputs.borrow_mut().insert(new_index, v.clone());
}

Ok(of.unwrap().borrow().get().clone())
Ok(of.unwrap().unwrap().borrow().get().clone())
}

}

impl<I> Netlist<I>
Expand Down
2 changes: 1 addition & 1 deletion tests/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ fn test_detect_cycles() {
let inverted = netlist
.insert_gate(inverter, "inst_0".into(), std::slice::from_ref(&input))
.unwrap();
assert!(netlist.replace_net_uses(input.unwrap(), &inverted).is_ok());
assert!(netlist.replace_net_uses(input, &inverted.get_output(0)).is_ok());

// Now there is a cycle.
// We replaced the inverter input with invert output.
Expand Down
4 changes: 2 additions & 2 deletions tests/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ fn test_replace_gate_bad() {
let or_gate = netlist
.insert_gate(or_gate, "inst_0".into(), &inputs)
.unwrap();
assert!(netlist.replace_net_uses(and_gate, &or_gate).is_ok());
assert!(netlist.replace_net_uses(and_gate.into(), &or_gate.into()).is_ok());
// Both the AND and OR gate are driving the same wire name (subtle).
// The instance name has to be different, or the user has to manualy rename it.
// Will need to consider how to make this more user-friendly.
Expand All @@ -379,7 +379,7 @@ fn test_replace_gate() {
let or_gate = netlist
.insert_gate(or_gate, "inst_0".into(), &inputs)
.unwrap();
assert!(netlist.replace_net_uses(and_gate, &or_gate).is_ok());
assert!(netlist.replace_net_uses(and_gate.into(), &or_gate.clone().into()).is_ok());
assert!(netlist.clean().is_err());
or_gate.set_instance_name("inst_1".into());
or_gate.as_net_mut().set_identifier("inst_1_Y".into());
Expand Down
126 changes: 124 additions & 2 deletions tests/edits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ fn and_gate() -> Gate {
Gate::new_logical("AND".into(), vec!["A".into(), "B".into()], "Y".into())
}

fn or_gate() -> Gate {
Gate::new_logical("OR".into(), vec!["A".into(), "B".into()], "Y".into())
}

fn two_out_gate() -> Gate {
// Simple 2-output primitive: one input "I" and two outputs "O0", "O1"
Gate::new_logical_multi(
"DUP".into(),
vec!["I".into()],
vec!["O0".into(), "O1".into()],
)
}

fn get_simple_example() -> Rc<GateNetlist> {
let netlist = Netlist::new("example".to_string());

Expand Down Expand Up @@ -48,7 +61,7 @@ fn test_replace() {
let inverted = netlist
.insert_gate(inverter, "inst_0".into(), std::slice::from_ref(&input))
.unwrap();
assert!(netlist.replace_net_uses(input.unwrap(), &inverted).is_ok());
assert!(netlist.replace_net_uses(input, &inverted.into()).is_ok());
assert_verilog_eq!(
netlist.to_string(),
"module example (
Expand Down Expand Up @@ -89,7 +102,7 @@ fn test_replace2() {
// This errors, because input is not safe to delete. No replace is done.
assert!(
netlist
.replace_net_uses(input.clone().unwrap(), &inverted)
.replace_net_uses(input.clone(), &inverted.clone().into())
.is_err()
);
inverted.find_input(&"I".into()).unwrap().connect(input);
Expand Down Expand Up @@ -121,3 +134,112 @@ fn test_replace2() {
endmodule\n"
);
}
// Testing edits for replace_net_uses using single and multiple output netrefs that have a
// DrivenNet that is fed as an argument
// TEST 1: SINGLE , SINGLE
// TEST2: SINGLE, MULTIPLE
// TEST3 MULTIPLE, SINGLE
// TEST4 MULTOPLE, MULTIPLE

#[test]
fn test_replace_single_single(){
let netlist = Netlist::new("example".into());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());
let and_inst = netlist.insert_gate(and_gate(), "and_0".into(), &[a.clone(), b]).unwrap();
let and_out = and_inst.get_output(0); // DrivenNet from a net ref of single output
// Ensure the netlist has a top-level output for verification
let and_out = and_out.expose_with_name("y".into());
// Drop the source node handle to satisfy the strong-count guard
drop(and_inst);
assert!(netlist.replace_net_uses(and_out, &a.clone()).is_ok());
assert!(netlist.verify().is_ok());
println!("{}", netlist.to_string());
}

#[test]
fn test_replace_single_single_v2(){
let netlist = Netlist::new("example".into());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());
let and_inst = netlist.insert_gate(and_gate(), "and_0".into(), &[a.clone(), b.clone()]).unwrap();
let or_inst = netlist.insert_gate(or_gate(),"or_0".into(), &[a.clone(),b.clone()]).unwrap();
let and_out = and_inst.get_output(0);
drop(and_inst);
assert!(netlist.replace_net_uses(and_out, &or_inst.clone().into()).is_ok());
or_inst.get_output(0).expose_with_name("y".into());
assert!(netlist.verify().is_ok());
println!("{}", netlist.to_string());
}
#[test]
fn test_replace_single_multiple(){
let netlist = Netlist::new("example".into());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());

let and_inst = netlist
.insert_gate(and_gate(), "and_0".into(), &[a.clone(), b.clone()])
.unwrap();

let dup = netlist
.insert_gate(two_out_gate(), "dup0".into(), &[a.clone()])
.unwrap();

dup.get_output(1).expose_with_name("y".into());

let and_out = and_inst.get_output(0);
let dup_out1 = dup.get_output(1);
drop(dup);
netlist.replace_net_uses(dup_out1, &and_out.clone()).unwrap();
assert!(netlist.verify().is_ok());
println!("{}", netlist);
}
#[test]
fn test_replace_multiple_single(){
let netlist = Netlist::new("example".into());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());

let and_inst = netlist
.insert_gate(and_gate(), "and_0".into(), &[a.clone(), b.clone()])
.unwrap();

let dup = netlist
.insert_gate(two_out_gate(), "dup0".into(), &[a.clone()])
.unwrap();

and_inst.get_output(0).expose_with_name("y".into());

let and_out = and_inst.get_output(0);
let dup_out0 = dup.get_output(0);
drop(and_inst);
netlist.replace_net_uses(and_out, &dup_out0.clone()).unwrap();
assert!(netlist.verify().is_ok());
println!("{}", netlist);

}

#[test]
fn test_replace_multiple_multiple(){
let netlist = Netlist::new("example".into());
let a = netlist.insert_input("a".into());

let dup1 = netlist
.insert_gate(two_out_gate(), "dup1".into(), &[a.clone()])
.unwrap();

let dup2 = netlist
.insert_gate(two_out_gate(), "dup2".into(), &[a.clone()])
.unwrap();

let dup1_out0 = dup1.get_output(0);
dup1_out0.clone().expose_with_name("y".into());
let dup2_out1 = dup2.get_output(1);

drop(dup2);
netlist.replace_net_uses(dup2_out1, &dup1_out0.clone()).unwrap();
assert!(netlist.verify().is_ok());
println!("{}", netlist);

}