Search code examples
verilogfpgaxilinxhdlvivado

Why does the Inferred Latch error occur during the synthesis process?


I think I've written all the cases for switch and if, but I don't understand why following message occur in synthesis process.

warnings messages

This module performs the operation of converting BCD code into excess-3 code. In behavior simulation, it works operately. but in post synthesis simulation, it works wrong.

`timescale 1ns/1ps

module fsm_ex3 (
    input sw1,
    input sw2,
    input clk,
    input reset_n,
    output reg [3:0] LED
);

localparam S_0 = 3'b000;
localparam S_1 = 3'b001;
localparam S_2 = 3'b010;
localparam S_3 = 3'b011;
localparam S_4 = 3'b100;
localparam S_5 = 3'b101;
localparam S_6 = 3'b110;


reg sw1_signal1,sw1_signal2,sw2_signal1,sw2_signal2;
wire o_sw1, o_sw2;


always @(posedge clk) begin
    sw1_signal1 <= sw1;
    sw2_signal1 <= sw2;
    sw1_signal2 <= sw1_signal1;
    sw2_signal2 <= sw2_signal1;
end

assign o_sw1 = sw1_signal1 && ~sw1_signal2;
assign o_sw2 = sw2_signal1 && ~sw2_signal2;


reg [2:0] c_state;
reg [2:0] n_state;

always @(posedge clk, negedge reset_n) begin
    if(!reset_n) begin
    c_state <= S_0;
    end
    else
    c_state <= n_state;
end

always @(*) begin
    case (c_state)
    S_0:begin
        if(o_sw1&&~o_sw2) begin
            n_state <= S_1;
            LED <= 4'b0001;
        end
        else if(~o_sw1&&o_sw2) begin
            n_state <= S_2;
            LED <= 4'b0000;
        end
        else  begin 
            n_state <= S_0;
            LED <= LED;
        end
    end
    S_1:begin
        if(o_sw1&&~o_sw2) begin
            n_state <= S_3;
            LED[1] <= 1;
        end
        else if(~o_sw1&&o_sw2) begin 
            n_state <= S_4;
            LED[1] <= 0;
        end 
        else begin 
            n_state <= S_1;
            LED <= LED;
        end
    end
    S_2:begin       
        if(o_sw1&&~o_sw2) begin 
            LED[1] <= 0;
            n_state <= S_4;
        end
        else if(~o_sw1&&o_sw2) begin 
            LED[1] <= 1;
            n_state <= S_4;
        end
        else begin 
            n_state <= S_2;
            LED <= LED;
        end
    end 
    S_3:begin
        if(o_sw1&&~o_sw2) begin 
            LED[2] <= 0;
            n_state <= S_5;
        end
        else if(~o_sw1&&o_sw2) begin 
            LED[2] <= 1;
            n_state <= S_5;
        end
        else begin 
            n_state <= S_3;
            LED <= LED;
        end
    end
    S_4:begin
        if(o_sw1&&~o_sw2) begin
             n_state <= S_5;
             LED[2] <= 1;
        end
        else if(~o_sw1&&o_sw2) begin
            n_state <= S_6;
            LED[2] <= 0;
        end
        else begin
            n_state <= S_4;
            LED <= LED;
        end     
    end
    S_5:begin 
        if(o_sw1&&~o_sw2) begin 
            LED[3] <= 0;
            n_state <= S_0;
        end
        else if(~o_sw1&&o_sw2) LED[3] <= 1;
        else begin
            n_state <= S_5;
            LED <= LED;
        end
    end
    S_6:begin
        if(o_sw1&&~o_sw2) begin
        n_state <= S_0;
        LED[3] <= 1;
        end
        else begin
        n_state <= n_state;
        LED <= LED;
        end
    end
    default: begin
     n_state <= n_state;
     LED <= LED;
     end
    endcase
end


endmodule

i using always(*) and write all cases but nothing change.


Solution

  • If you separate the design into 2 blocks, updating and evaluation, the code may look like this:

    // Updating phase
    reg [3:0] n_LED;
    always @( posedge clk or negedge reset_n )
        if ( ~reset_n )
            { c_state, LED } <= { S_0, 4'b0000 };
        else
            { c_state, LED } <= { n_state, n_LED };
    
    // Evaluation phase
    always @*
    begin
        { n_state, n_LED } = { c_state, LED };  // Default
        case ( c_state )
            ...
            S_5: begin
                if ( o_sw1 && ( ~o_sw2 ) ) begin 
                    n_LED[3] = 0;
                    n_state = S_0;
                end
                else if ( ( ~o_sw1 ) && o_sw2 )
                    n_LED[3] = 1;
                else
                    n_state = S_5;
            end
            ...
        endcase
    end
    

    In the updating phase, the next state is assigned to current state (DFF D -> Q).

    In the evaluation phase, the next state is derived from current state or other variables (DFF Q -> D). Use "=" instead of "<=" because this block comprises combinational logic. There is a default assignment at the beginning of this block. So if some variables are not assigned in the case branches, that would be no problem since all variables have already got their default values.