f4pga / f4pga-arch-defs

FOSS architecture definitions of FPGA hardware useful for doing PnR device generation.
https://f4pga.org
ISC License
270 stars 112 forks source link

Incorrect PLL-BUFG-BUFGMUX handling #1645

Open rw1nkler opened 4 years ago

rw1nkler commented 4 years ago

During the work on merging #1419 I figured out that the basic BUFGMUX example works differently on Arty Board and Nexys Video.

The example uses three LEDs:

On the Arty Board, the example works as intended. On Nexys Video, when the switch is set to led[2] frequency, the led[0] stops to blink. The same error was occurring for the Basys3 board.

The failing example was the following:

module top (
    input  wire clk,

    input  wire [7:0] sw,
    output wire [7:0] led,
);
    wire O_LOCKED;
    wire RST;

    wire clk0;
    wire clk1;
    wire clk_out;
    wire clk_fb_i;
    wire clk_fb_o;

    reg [25:0] cnt_clk_out;
    reg [25:0] cnt_clk0;
    reg [25:0] cnt_clk1;

    assign RST = 1'b0;

    BUFG bufg0 (
        .I(clk_fb_i),
        .O(clk_fb_o)
    );

    wire clk_ibuf;
    IBUF ibuf0 (
        .I(clk),
        .O(clk_ibuf)
    );

    wire clk_bufg;
    BUFG bufg1 (
        .I(clk_ibuf),
        .O(clk_bufg)
    );

    PLLE2_ADV #(
        .BANDWIDTH          ("HIGH"),
        .COMPENSATION       ("ZHOLD"),

        .CLKIN1_PERIOD      (10.0),  // 100MHz

        .CLKFBOUT_MULT      (8),
        .CLKOUT0_DIVIDE     (8),
        .CLKOUT1_DIVIDE     (8 * 4),

        .STARTUP_WAIT       ("FALSE"),

        .DIVCLK_DIVIDE      (1)
    )
    pll (
        .CLKIN1     (clk_bufg),
        .CLKINSEL   (1),

        .RST        (RST),
        .PWRDWN     (0),
        .LOCKED     (O_LOCKED),

        .CLKFBIN    (clk_fb_i),
        .CLKFBOUT   (clk_fb_o),

        .CLKOUT0    (clk0),
        .CLKOUT1    (clk1)
    );

    wire clk0_bufg;
    BUFG bufg2 (
        .I(clk0),
        .O(clk0_bufg)
    );

    wire clk1_bufg;
    BUFG bufg3 (
        .I(clk1),
        .O(clk1_bufg)
    );

    BUFGMUX bufgmux (
      .I0(clk0_bufg),
      .I1(clk1_bufg),
      .S(sw[0]),
      .O(clk_out)
    );

    always @(posedge clk_out) begin
        cnt_clk_out <= cnt_clk_out + 1'b1;
    end
    assign led[0] = cnt_clk_out[25];

    always @(posedge clk0_bufg) begin
        cnt_clk0 <= cnt_clk0 + 1'b1;
    end
    assign led[1] = cnt_clk0[25];

    always @(posedge clk1_bufg) begin
        cnt_clk1 <= cnt_clk1 + 1'b1;
    end
    assign led[2] = cnt_clk1[25];
endmodule

It turned out that the problem is related to the intermediate BUFG, which connects PLL and BUFGMUX. Since the BUFGMUX is also a buffer, I removed the additional BUFG, which resolved the problem. Nevertheless, the failing example can be handled properly by Vivado.

In SymbiFlow the correct BUFGMUX nets are connected through BUFHCE. For some reason, the failing net in case of Nexys Video is connected directly to BUFG output.

A correct BUFGMUX input net: correct

A failing BUFGMUX input net: failure

Both examples were passing the diff_fasm step. In the recent BUFGMUX test, the additional BUFG has been removed which resolved the issue. Still, the inconsistent behavior may indicate that there is a bug in the tools.

litghost commented 3 years ago

This bug is a result of Vivado not handling explicit BUFHCE's which is equivilant from a bitstream standpoint from using the BUFHCE site route-through psuedo pip. The solution to this bug is to change how fasm2bels handles this. In the case where a BUFHCE site is configured as a route through (e.g. BUFHCE(.CE(1'b1), ...)), then fasm2bels should enable the pseudo pip rather than emitting a BUFHCE cell.

There are examples of how this is done for the ILOGIC and OLOGIC sites here:

https://github.com/SymbiFlow/symbiflow-xc-fasm2bels/blob/8fa587570df242de48cbf67f214bbb5d45af07ef/fasm2bels/models/ioi_models.py#L740-L742

GitHub
SymbiFlow/symbiflow-xc-fasm2bels
Library to convert a FASM file into BELs importable into Vivado. - SymbiFlow/symbiflow-xc-fasm2bels