spydrnet
spydrnet copied to clipboard
Flatten cannot handle multiple instances of one definition in another definition.
Here is the hierarchy structure of instances, and in the parentheses is the corresponding definition.
top |- inst0 (Foo) `- inst1 (Foo)
Foo `- inv (INV)
The flatten function cannot handle this case, because it remove cables and pins in Foo when meet top/inst0. Then when meet inst1, it cannot reconnect the wires again for top/inst1
Here is an example.
Generate EDIF:
import spydrnet as sdn
netlist = sdn.Netlist(name='netlist')
prim_library = netlist.create_library(name="hdi_primitives")
INV_def = prim_library.create_definition(name="INV")
INV_port_output = INV_def.create_port(name="O", direction=sdn.OUT)
INV_port_input = INV_def.create_port(name="I", direction=sdn.IN)
INV_pin_output = INV_port_output.create_pin()
INV_pin_input = INV_port_input.create_pin()
work_library = netlist.create_library(name="work")
Foo_def = work_library.create_definition(name='Foo')
Foo_port_output = Foo_def.create_port(name="O", direction=sdn.OUT)
Foo_port_input = Foo_def.create_port(name="I", direction=sdn.IN)
Foo_pin_output = Foo_port_output.create_pin()
Foo_pin_input = Foo_port_input.create_pin()
INV_inst = Foo_def.create_child(name='inv', reference=INV_def)
Foo_cable_0 = Foo_def.create_cable(name='cable_in_Foo_0')
Foo_wire_0 = Foo_cable_0.create_wire()
Foo_cable_1 = Foo_def.create_cable(name='cable_in_Foo_1')
Foo_wire_1 = Foo_cable_1.create_wire()
Foo_wire_0.connect_pin(INV_inst.pins[INV_pin_input])
Foo_wire_0.connect_pin(Foo_pin_input)
Foo_wire_1.connect_pin(INV_inst.pins[INV_pin_output])
Foo_wire_1.connect_pin(Foo_pin_output)
top_def = work_library.create_definition(name='top')
top_port_output_0 = top_def.create_port(name="O0", direction=sdn.OUT)
top_port_output_1 = top_def.create_port(name="O1", direction=sdn.OUT)
top_port_input_0 = top_def.create_port(name="I0", direction=sdn.IN)
top_port_input_1 = top_def.create_port(name="I1", direction=sdn.IN)
ports = [top_port_output_0, top_port_output_1,
top_port_input_0, top_port_input_1]
inner_pins = [port.create_pin() for port in ports]
foo_inst_0 = top_def.create_child(name='foo0', reference=Foo_def)
foo_inst_1 = top_def.create_child(name='foo1', reference=Foo_def)
outter_pins = [
foo_inst_0.pins[Foo_pin_output], foo_inst_1.pins[Foo_pin_output],
foo_inst_0.pins[Foo_pin_input], foo_inst_1.pins[Foo_pin_input]
]
cables, wires = [], []
for i in range(4):
cables.append(top_def.create_cable(name=f'cable_in_top_{i}'))
for cable in cables:
wires.append(cable.create_wire())
for wire, inner_pin, outter_pin in zip(wires, inner_pins, outter_pins):
wire.connect_pin(inner_pin)
wire.connect_pin(outter_pin)
netlist.set_top_instance(top_def, instance_name=top_def.name)
sdn.compose(netlist, 'demo.edif')
EDIF:
(edif netlist
(edifversion 2 0 0)
(edifLevel 0)
(keywordmap (keywordlevel 0))
(status
(written
(timeStamp 2024 02 14 17 47 02)
(comment "Built by 'BYU spydrnet tool'")
)
)
(Library hdi_primitives
(edifLevel 0)
(technology (numberDefinition ))
(Cell INV (celltype GENERIC)
(view netlist (viewtype NETLIST)
(interface
(port O(direction OUTPUT))
(port I(direction INPUT))
)
)
)
)
(Library work
(edifLevel 0)
(technology (numberDefinition ))
(Cell Foo (celltype GENERIC)
(view netlist (viewtype NETLIST)
(interface
(port O(direction OUTPUT))
(port I(direction INPUT))
)
(contents
(instance inv (viewref netlist (cellref INV(libraryref hdi_primitives)))
)(net cable_in_Foo_0 (joined
(portref I (instanceref inv))
(portref I)
)
)(net cable_in_Foo_1 (joined
(portref O (instanceref inv))
(portref O)
)
))
)
)
(Cell top (celltype GENERIC)
(view netlist (viewtype NETLIST)
(interface
(port O0(direction OUTPUT))
(port O1(direction OUTPUT))
(port I0(direction INPUT))
(port I1(direction INPUT))
)
(contents
(instance foo0 (viewref netlist (cellref Foo(libraryref work)))
)(instance foo1 (viewref netlist (cellref Foo(libraryref work)))
)(net cable_in_top_0 (joined
(portref O0)
(portref O (instanceref foo0))
)
)(net cable_in_top_1 (joined
(portref O1)
(portref O (instanceref foo1))
)
)(net cable_in_top_2 (joined
(portref I0)
(portref I (instanceref foo0))
)
)(net cable_in_top_3 (joined
(portref I1)
(portref I (instanceref foo1))
)
))
)
)
)
(design top
(cellref top(libraryref work))
)
)
Flatten Netlist:
//Generated from netlist by SpyDrNet
//netlist name: netlist
module top
(
.O0({cable_in_top_0}),
.O1({cable_in_top_1}),
.I0({cable_in_top_2}),
.I1({cable_in_top_3})
);
output cable_in_top_0;
output cable_in_top_1;
input cable_in_top_2;
input cable_in_top_3;
wire foo0/cable_in_Foo_1;
wire foo0/cable_in_Foo_0;
wire cable_in_top_3;
wire cable_in_top_2;
wire cable_in_top_1;
wire cable_in_top_0;
INV foo1/foo0/inv <==== ERROR HERE
(
.O(cable_in_top_0),
.I(cable_in_top_2)
);
endmodule
`celldefine
module INV
(
O,
I
);
output O;
input I;
endmodule
`endcelldefine
module Foo
(
O,
I
);
output O;
input I;
endmodule
Thanks for posting this. This definitely needs to be fixed.
A quick fix for now should could be to uniquify the netlist before flattening.
from spydrnet.uniquify import uniquify
uniquify(netlist)
flatten(netlist)
sdn.compose(netlist, "demo_flat_uniquify.v")
The result is
//Generated from netlist by SpyDrNet
//netlist name: netlist
module top
(
.O0({cable_in_top_0}),
.O1({cable_in_top_1}),
.I0({cable_in_top_2}),
.I1({cable_in_top_3})
);
output cable_in_top_0;
output cable_in_top_1;
input cable_in_top_2;
input cable_in_top_3;
wire foo1/cable_in_Foo_1;
wire foo1/cable_in_Foo_0;
wire foo0/cable_in_Foo_1;
wire foo0/cable_in_Foo_0;
wire cable_in_top_3;
wire cable_in_top_2;
wire cable_in_top_1;
wire cable_in_top_0;
INV foo0/inv
(
.O(cable_in_top_0),
.I(cable_in_top_2)
);
INV foo1/inv
(
.O(cable_in_top_1),
.I(cable_in_top_3)
);
endmodule
Looking at it a little closer, it seems that you must run uniquify before flattening. So I don't think this is a bug. The documentation should be improved to indicate the uniquify requirement.