有人可以解释为什么这会导致组合反馈循环吗? (维瓦多 Verilog)

Can someone please explain why this causes a combinational feedback loop? (Vivado Verilog)

一些基本背景:我有一个显示驱动程序,需要处理一些输入并将结果显示在分段显示器上。通过在 'statusDisplay' 中设置数值来更新分段显示。我已将此代码简化为显示驱动程序并尝试显示一个简单的计数器。

使用分段显示令人兴奋,但它确实有效。但是,一旦我尝试在 statusDisplay 寄存器中放入一个值,Vivado 就会说存在组合反馈循环。对于我的生活,我无法弄清楚为什么或如何解决它。

我什至创建了一些测试代码,它们基本上做同样的事情并且没有导致问题。

奇怪的是,编译器也在行 'ticker1 <= ticker1+1' 上报告了问题,但仅删除行 'valueToDisplay <= bigCounter' 就解决了问题。

谢谢!!!

timescale 1ns / 1ps

module circuit1_top(
    input clk,
    output [15:0] LED,      // Create two outputs
    output [7:0] SSEG_CA,
    output [7:0] SSEG_AN
    );

    reg [31:0] counter = 32'h0; 
    reg [0:0] divclk = 1'b0;
    reg [0:0] showclk= 1'b0;

    reg [15:0] caseCounter = 15'b0;
    reg [15:0] LedReg=0;
    reg [7:0] SegReg;
    reg [7:0] DigReg;
    reg [31:0] Hex = 0;

    reg [0:0] segclk = 1'b0, scroll = 1'b0;
    reg [31:0] displayNumber;
    reg [2:0] segNumber = 3'b0;

    reg [31:0] statusDisplay;
    reg [31:0] display1, display2, display3, display4, display5, display6, display7, display8, display9, display10;

    reg [31:0] ticker1=0;

    initial 
    begin
        scroll = 0;
        displayNumber = 32'hDEADBEEF;
        statusDisplay = 32'h80085;
        display1=1;
        display2=2;
        display3=3;
        display4=4;
        display5=5;
        display6=6;
        display7=7;
        display8=8;
        display9=9;
        display10=10;
    end

    // Testing simpler similar code - this does not create a loop problem
    reg [31:0] bigCounter=0;
    reg [31:0] valueToDisplay=0;
    reg [31:0] displayRegister=0;

    always @(clk)
    begin
        bigCounter <= bigCounter + 1;
        if( (bigCounter & 32'h7FFF) == 32'h7FFF )
            valueToDisplay <= bigCounter;
    end

    always @(clk)
    begin
        displayRegister <= valueToDisplay;
    end
    // End Test Code


    always @(clk)
    begin
        ticker1 <= ticker1 + 1;     //. <<—- This line is reported as causing the problem
        if( (ticker1 & 32'h7FFF) == 32'h7FFF )
            statusDisplay <= ticker1 + 1;   // <<—- Removing this line actually solves the problem
    end

        // Display driver starts here...

        // Retrieve display segments based on number to display
    task automatic getSegments;
        input [7:0] number;
        output [7:0] segment_ca;

        begin
           case (number)
              4'h0 :segment_ca <= 8'b11000000;       // 0                     
              4'h1 :segment_ca <= 8'b11111001;       // 1                       
              4'h2 :segment_ca <= 8'b10100100;       // 2                       
              4'h3 :segment_ca <= 8'b10110000;       // 3                       
              4'h4 :segment_ca <= 8'b10011001;       // 4                       
              4'h5 :segment_ca <= 8'b10010010;       // 5                       
              4'h6 :segment_ca <= 8'b10000010;       // 6                       
              4'h7 :segment_ca <= 8'b11111000;       // 7                       
               4'h8 :segment_ca <= 8'b10000000;       // 8                        
               4'h9 :segment_ca <= 8'b10010000;       // 9                        
               4'hA :segment_ca <= 8'b10001000;       // A                        
               4'hB :segment_ca <= 8'b10000011;       // b                        
               4'hC :segment_ca <= 8'b11000110;       // C                        
               4'hD :segment_ca <= 8'b10100001;       // d                        
               4'hE :segment_ca <= 8'b10000110;       // E
               4'hF :segment_ca <= 8'b10001110;       // F
              default: begin end
           endcase
          end
    endtask



assign SSEG_AN = DigReg;
assign SSEG_CA = SegReg;


always @(posedge segclk)
    segNumber <= segNumber + 1;


always @(posedge segclk)      
    begin
    case( segNumber )
         4'h0: begin  DigReg <= ~(32'h1);             getSegments( displayNumber & 4'b1111, SegReg ); end
         4'h1: begin  DigReg <= ~(((displayNumber < 32'h10 ? 1'b0 : 1'b1) & 32'h1) << 1);        getSegments( (displayNumber>>4) & 4'b1111, SegReg ); end
         4'h2: begin  DigReg <= ~(((displayNumber < 32'h100 ? 1'b0 : 1'b1) & 32'h1) << 2);        getSegments( (displayNumber>>8) & 4'b1111, SegReg ); end
         4'h3: begin  DigReg <= ~(((displayNumber < 32'h1000 ? 1'b0 : 1'b1) & 32'h1) << 3);        getSegments( (displayNumber>>12) & 4'b1111, SegReg ); end
         4'h4: begin  DigReg <= ~(((displayNumber < 32'h10000 ? 1'h0 : 1'h1) & 32'h1) << 4);        getSegments( (displayNumber>>16) & 4'b1111, SegReg ); end
         4'h5: begin  DigReg <= ~(((displayNumber < 32'h100000 ? 1'h0 : 1'h1) & 32'h1) << 5);        getSegments( (displayNumber>>20) & 4'b1111, SegReg ); end
         4'h6: begin  DigReg <= ~(((displayNumber < 32'h1000000 ? 1'h0 : 1'h1) & 32'h1) << 6);        getSegments( (displayNumber>>24) & 4'b1111, SegReg ); end
         4'h7: begin  DigReg <= ~(((displayNumber < 32'h10000000 ? 1'h0 : 1'h1) & 32'h1) << 7);        getSegments( (displayNumber>>28) & 4'b1111, SegReg ); end
          default: begin end

    endcase

    end




////clock divider////    
         always @(posedge clk)
         begin
            if( (counter & 16'h7FFF) == 16'h7FFF ) begin
                segclk <= ~segclk;      // Switch to the next segment in the display

            end

            if(counter == 32'h17D7840) begin    // 1/4 second, so change every 1/2 second...
                counter <= 32'h0;               // This only really matters if we are scrolling             divclk <= ~divclk;
            end
            else begin
                counter <= counter + 1'b1;
            end
        end

        always @(posedge divclk) 
               begin

                if(caseCounter == 9) begin    // Over it!!
                    caseCounter <= 0;
                end
                else begin
                    caseCounter <= caseCounter + 1'b1;
                end


               end

        always @(posedge divclk)  
        begin

            if( scroll )    // Scroll through ten potential outputs display
            begin
                case( caseCounter )
                0: displayNumber <= display1;
                1: displayNumber <= display2;
                2: displayNumber <= display3;
                3: displayNumber <= display4;
                4: displayNumber <= display5;
                5: displayNumber <= display6;
                6: displayNumber <= display7;
                7: displayNumber <= display8;
                8: displayNumber <= display9;
                9: displayNumber <= display10;
                default ;
                endcase
                LedReg <= 1 << caseCounter;
            end
            else
                displayNumber <= statusDisplay; // This is the only access to statusDisplay
             end

        assign LED = LedReg;

endmodule

我猜你跳过了模拟,直接进入了综合。 always @(clk) 应该是 always @(posedge clk)

与模拟器不同,合成器并不严格遵循敏感度列表。合成器寻找关键字 posedgenegedge 来决定逻辑是否应该是同步的(然后其他步骤来确定它是否是异步控制)。否则它假定异步。

照原样,合成器将忽略选择性列表,然后将 ticker1 <= ticker1+1 视为反馈循环。删除 statusDisplay <= ticker1 + 1 sudo 解决了这个问题,因为 ticker1 没有在其他任何地方被引用,因此它被优化掉了。

always @(posedge clk)
begin
    ticker1 <= ticker1 + 1;
    if( (ticker1 & 32'h7FFF) == 32'h7FFF )
        statusDisplay <= ticker1 + 1;
end