Xilinx / RapidWright

Build Customized FPGA Implementations for Vivado
http://www.rapidwright.io
Other
290 stars 108 forks source link

Error in SiteInst.routeSite on Spartan 7 #179

Closed trharoldsen closed 3 years ago

trharoldsen commented 3 years ago

Working with Spartan 7, I have a site instance that fails when I call routeSite on it.

Exception in thread "main" java.lang.RuntimeException: ERROR: Unable to route failing_net in site SLICE_X11Y46
    at com.xilinx.rapidwright.design.SiteInst.routeSite(Unknown Source)

The site is routing the D5LUT out through the DMUX output.

D5 -> [D5LUT] -> DMUX

Doing some debugging, this particular net seems to be the failing point. Digging a little further, it looks like the code is trying to route through the DFFMUX instead of the DOUTMUX.

I've included what I believe are the relevant pieces of information but the site below.

siteInst.getSiteTypeEnum(): SLICEL
siteInst.getCells(): [test_SLICE_X11Y46_D5LUT(BEL: D5LUT)]
siteInst.getSitePinInstMap(): {D5=driver_net, D6=GLOBAL_LOGIC1, DMUX=failing_net}

driver_net drives the D5LUT; failing_net comes out of the D5LUT.O output pin and out through the DMUX.

clavin-xlnx commented 3 years ago

I'm having trouble reproducing the issue. Can you provide a test case or modify the code below to trigger the issue?

        Design design = new Design("testcase","xc7s25csga324");
        EDIFCell top = design.getNetlist().getTopCell();
        Cell lut1 = design.createAndPlaceCell("test_SLICE_X11Y46_D5LUT", Unisim.LUT1, "SLICE_X11Y46/D5LUT");

        Net driverNet = design.createNet("driver_net");
        Net failingNet = design.createNet("failing_net");

        driverNet.connect(lut1, "I0");
        failingNet.connect(lut1, "O");
        driverNet.getLogicalNet().createPortInst(top.createPort("dummyIn", EDIFDirection.INPUT, 1));
        failingNet.getLogicalNet().createPortInst(top.createPort("dummyOut", EDIFDirection.OUTPUT, 1));

        driverNet.createPin(false, "D5", lut1.getSiteInst());
        design.getVccNet().addPin(new SitePinInst("D6", lut1.getSiteInst()));
        failingNet.createPin(false, "DMUX", lut1.getSiteInst());

        lut1.getSiteInst().routeSite();

        design.writeCheckpoint(design.getName() +".dcp");  
trharoldsen commented 3 years ago

I haven't quite been able to create a duplicate example though I'm working on it. In the process, I've discovered an oddity while working with your example above.

First, your DMUX is being created as an input instead of an output. Fixing them, looking through the data structures, the above code causes two version of the DMUX SitePinInst to be created. One instance resides in fields on the Net. The other resides in fields on the SiteInst. The objects reference the same pin, but are two different objects.

I notice what appears to be a bug here as the instance related to the Net contains a reference back to the Net but the instance related to the SiteInst does not have this reference back to the Net.

I'm checking the out this difference to determine to see if this is the source of this other error I'm seeing.

Below if the code with the DMUX output issue fixed.

        Design design = new Design("testcase","xc7s25csga324");
        EDIFCell top = design.getNetlist().getTopCell();
        Cell lut1 = design.createAndPlaceCell("test_SLICE_X11Y46_D5LUT", Unisim.LUT1, "SLICE_X11Y46/D5LUT");

        Net driverNet = design.createNet("driver_net");
        Net failingNet = design.createNet("failing_net");

        driverNet.connect(lut1, "I0");
        failingNet.connect(lut1, "O");
        driverNet.getLogicalNet().createPortInst(top.createPort("dummyIn", EDIFDirection.INPUT, 1));
        failingNet.getLogicalNet().createPortInst(top.createPort("dummyOut", EDIFDirection.OUTPUT, 1));

        driverNet.createPin(false, "D5", lut1.getSiteInst());
        design.getVccNet().addPin(new SitePinInst("D6", lut1.getSiteInst()));
        failingNet.createPin(false, "DMUX", lut1.getSiteInst());

        lut1.getSiteInst().routeSite();

        design.writeCheckpoint(design.getName() +".dcp");  
trharoldsen commented 3 years ago

Found a failing minimal example by removing disconnecting the output to a top level port and replacing it with a connection to another LUT. The previous noted issue with the pin instance not referencing the connected net did not appear to have an effect on this particular error.

        Design design2 = new Design("testcase","xc7s25csga324");
        EDIFCell top = design2.getNetlist().getTopCell();
        Cell lut1 = design2.createAndPlaceCell("test_SLICE_X7Y46_D5LUT", Unisim.LUT1, "SLICE_X7Y46/D5LUT");
        Cell lut2 = design2.createAndPlaceCell("test_SLICE_X11Y46_D6LUT", Unisim.LUT1, "SLICE_X11Y46/D6LUT");  // added

        Net driverNet = design2.createNet("driver_net");
        Net failingNet = design2.createNet("failing_net");

        driverNet.connect(lut1, "I0");
        failingNet.connect(lut1, "O");
        failingNet.connect(lut2, "I0");  // added
        driverNet.getLogicalNet().createPortInst(top.createPort("dummyIn", EDIFDirection.INPUT, 1));
//        failingNet.getLogicalNet().createPortInst(top.createPort("dummyOut", EDIFDirection.OUTPUT, 1));

        driverNet.createPin(false, "D5", lut1.getSiteInst());
        design2.getVccNet().addPin(new SitePinInst("D6", lut1.getSiteInst()));
        failingNet.createPin(true, "DMUX", lut1.getSiteInst());
        failingNet.createPin(true, "D6", lut2.getSiteInst());  // added
        lut1.getSiteInst().getSitePinInst("DMUX").setNet(failingNet);

        lut1.getSiteInst().routeSite();

        design2.writeCheckpoint(design2.getName() +".dcp");
clavin-xlnx commented 3 years ago

Thanks @trharoldsen, I had a copy/paste typo for the output pin. That createPin() method should probably be deprecated and replaced with a version that doesn't require you to specify the direction as it can be determined by the pin name on the SiteInst. You've also correctly pointed out that createPin() isn't checking if the pin already exists on the SiteInst and so it creates a duplicate. It turns out the pin was already created in Net.connect() when attaching the output of the LUT.

From your updated code, I was able to track down the issue in the site router. It was handling a special case that I have fixed internally and will be in the next release. This issue seems to be Series 7 specific and was getting hung up on the D5FF which doesn't route out of the site directly. To work around the issue, you can also route the nets within the site directly, for example:

si.routeIntraSiteNet(failingNet, lut1.getBEL().getPin("O5"), si.getBEL("DMUX").getPin("DMUX"));

This will avoid the error until the release is made (hopefully next week).

clavin-xlnx commented 3 years ago

The 2020.2.5 release should fix this issue.