use safety_net::rewriter::NetMapper;
use safety_net::{
Identifier, Instantiable, Logic, Net, Netlist, Parameter, assert_verilog_eq, format_id,
};
#[derive(Debug, Clone)]
enum Gate {
And(Identifier, Vec<Net>, Net),
Inv(Identifier, Net, Net),
}
impl Instantiable for Gate {
fn get_name(&self) -> &Identifier {
match self {
Gate::And(id, _, _) | Gate::Inv(id, _, _) => id,
}
}
fn get_input_ports(&self) -> impl IntoIterator<Item = &Net> {
match self {
Gate::And(_, inputs, _) => inputs,
Gate::Inv(_, input, _) => std::slice::from_ref(input),
}
}
fn get_output_ports(&self) -> impl IntoIterator<Item = &Net> {
match self {
Gate::And(_, _, output) => std::slice::from_ref(output),
Gate::Inv(_, _, output) => std::slice::from_ref(output),
}
}
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> {
None
}
fn get_constant(&self) -> Option<Logic> {
None
}
fn is_seq(&self) -> bool {
false
}
}
fn and_gate() -> Gate {
Gate::And(
"AND".into(),
vec![Net::new_logic("A".into()), Net::new_logic("B".into())],
Net::new_logic("Y".into()),
)
}
fn inv_gate() -> Gate {
Gate::Inv(
"INV".into(),
Net::new_logic("A".into()),
Net::new_logic("Y".into()),
)
}
#[test]
fn test_matches_macro() {
let netlist = Netlist::new("example".to_string());
let a = netlist.insert_input("a".into());
let b = netlist.insert_input("b".into());
let instance = netlist
.insert_gate(and_gate(), "inst_0".into(), &[a, b])
.unwrap();
instance.expose_with_name("y".into());
let mut everything = Vec::new();
for node in netlist.objects() {
for output in node.outputs() {
everything.push(output);
}
}
let n = everything.len();
let mapper = NetMapper::new(&netlist);
assert!(mapper.is_ok());
let mut mapper = mapper.unwrap();
for (i, net) in everything.into_iter().enumerate() {
let inst_name = net.as_net().get_identifier().clone() + format_id!("_{i}_{n}");
let net_inv = netlist.insert_gate_disconnected(inv_gate(), inst_name.clone());
let inst_name = inst_name + "inv".into();
let net_inv_inv = netlist
.insert_gate(inv_gate(), inst_name, &[net_inv.clone().into()])
.unwrap();
let replacement = net_inv_inv.get_output(0);
let disconnected = mapper.replace(net, replacement);
net_inv.get_input(0).connect(disconnected);
}
let res = mapper.apply();
assert!(res.is_ok());
assert_verilog_eq!(
netlist.to_string(),
"module example (
a,
b,
y
);
input wire a;
input wire b;
output wire y;
wire a__0_3_Y;
wire a__0_3_inv_Y;
wire b__1_3_Y;
wire b__1_3_inv_Y;
wire inst_0_Y;
wire inst_0_Y__2_3_Y;
wire inst_0_Y__2_3_inv_Y;
AND inst_0 (
.A(a__0_3_inv_Y),
.B(b__1_3_inv_Y),
.Y(inst_0_Y)
);
INV a__0_3 (
.A(a),
.Y(a__0_3_Y)
);
INV a__0_3_inv (
.A(a__0_3_Y),
.Y(a__0_3_inv_Y)
);
INV b__1_3 (
.A(b),
.Y(b__1_3_Y)
);
INV b__1_3_inv (
.A(b__1_3_Y),
.Y(b__1_3_inv_Y)
);
INV inst_0_Y__2_3 (
.A(inst_0_Y),
.Y(inst_0_Y__2_3_Y)
);
INV inst_0_Y__2_3_inv (
.A(inst_0_Y__2_3_Y),
.Y(inst_0_Y__2_3_inv_Y)
);
assign y = inst_0_Y__2_3_inv_Y;
endmodule"
);
}