Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flatten cannot handle multiple instances of one definition in another definition. #220

Open
zhuguiyuan opened this issue Feb 14, 2024 · 2 comments
Labels
documentation Improvements or additions to documentation

Comments

@zhuguiyuan
Copy link

zhuguiyuan commented Feb 14, 2024

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
@jacobdbrown4
Copy link
Collaborator

jacobdbrown4 commented Feb 23, 2024

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

@jacobdbrown4 jacobdbrown4 added the bug Bug release issue label Feb 23, 2024
@jacobdbrown4
Copy link
Collaborator

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.

@jacobdbrown4 jacobdbrown4 added documentation Improvements or additions to documentation and removed bug Bug release issue labels Feb 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

2 participants