Может кто-нибудь объяснить, почему это вызывает комбинационную петлю обратной связи?(Вивадо Верилог) - PullRequest
0 голосов
/ 19 сентября 2019

Некоторый базовый фон: у меня есть драйвер дисплея, и мне нужно обработать некоторые входные данные и отобразить результаты на сегментированном дисплее.Сегментированный дисплей обновляется путем установки числового значения в «statusDisplay».Я упростил этот код до драйвера дисплея и пытался отобразить простой счетчик.

Использование сегментированного дисплея интересно, но оно работает.Но как только я пытаюсь поместить значение в регистр statusDisplay, Вивадо говорит, что существует комбинационная петля обратной связи.Что касается жизни, я не могу понять, почему или как это исправить.

Я даже создал некоторый тестовый код, который по сути делает то же самое, и это не приводит к проблеме.

Как ни странно, также компилятор сообщает о проблеме в строке 'ticker1 <= ticker1 + 1', но только удаление строки 'valueToDisplay <= bigCounter' решает проблему. </p>

Спасибо!!!

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

1 Ответ

2 голосов
/ 19 сентября 2019

Полагаю, вы пропустили симуляцию и пошли прямо к синтезу.always @(clk) должно быть always @(posedge clk)

В отличие от симуляторов, синтезаторы не строго следуют списку чувствительности.Синтезаторы ищут ключевые слова posedge и negedge, чтобы решить, должна ли логика быть синхронной (затем другие шаги, чтобы определить, является ли это асинхронным управлением).В противном случае это предполагает асинхронность.

Таким образом, синтезаторы проигнорируют список селективности, а затем увидят 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
...