Verilog 中推断锁存器(不是 else 或 default 语句)的原因

Cause of inferred latches (not else or default statement) in Verilog

Quartus 告诉我,我已经推断出 input_val、ii、output_val、延迟和 addr_to_rom 的锁存器。我查看了以前的帖子并进行了更改,以便我所有的 if 语句都有一个 else 组件并且我的 case 语句有一个默认选项。

还有什么可能导致所有这些推断的闩锁? (下面更新了代码)

   module   simple_fir(clk, reset_n, output_val); 
    
    parameter               data_width = 8; 
    parameter               size = 1024;    

    
    input   wire                clk;
    input   wire                reset_n;
    //input     reg [(data_width):0]    input_val;
    reg [(data_width):0]    input_val;
    output  reg [data_width:0]      output_val;

    reg     [(data_width):0]    delayed;
    reg     [data_width:0]      to_avg;     
    reg         [9:0]           ii ;
    reg         [9:0]           i ;
    reg     [data_width:0]      val;
    reg     [data_width:0]      output_arr [(size-1):0];

    
    logic [(data_width):0] data_from_rom; //precalculated 1 Hz sine wave
    logic [9:0] addr_to_rom;

    initial delayed = 0;
    initial i = 0;
    initial ii = 0;
    
    
    //port map to ROM
    rom_data input_data(
    .clk(clk),
    .addr(addr_to_rom), //text file?
    .data(data_from_rom)
    );
        
    //Moore FSM
    localparam [3:0]
    s0=0, s1 = 1, s2 = 2, s3 = 3, s4 = 4, s5 = 5, s6 = 6;
    
    reg [3:0] state_reg, state_next;
    initial state_next = 0;
    always @(posedge clk, negedge reset_n) begin //posedge clk, reset_n
        if (reset_n == 'b0) begin //reset is active low
        state_reg <= s0;
        end else begin
        state_reg <= state_next;
        end
    end
            
    always @* begin 
        state_next = state_reg; // default state_next
        case (state_reg)
            s0 : begin //initial state, reset state
                    if (!reset_n) begin
            output_val = 0;
            delayed = 0; 
            to_avg= 0; 
            i = 0;
            ii = 0;
            end else begin
            state_next = s1;
            end
            end
            s1 : begin
                if (ii>(size-2)) begin
                ii = 0;
                end else begin
                addr_to_rom = ii;
                end
                input_val = input_val;
                delayed = delayed; 
                state_next = s2;
            end
            s2 : begin
                input_val = data_from_rom;
                ii = ii+1;
                delayed = delayed; 
                state_next = s3;
            end
            s3 : begin
                delayed = input_val;
                state_next = s4;
            end
            s4 : begin
                addr_to_rom = ii;
                input_val = input_val;
                delayed = delayed; 
                state_next = s5;
            end
            s5 : begin
                input_val = data_from_rom;
                delayed = delayed;
                //i=i+1;
                //ii <= ii+1;
                state_next = s6;
            end
           s6 : begin
                to_avg = input_val + delayed; //summing two values
                val = (to_avg >> 1);    //taking the average
                output_arr[ii-1] = val; //indexing starts on [2]
                output_val = val; 
                state_next = s0;
                input_val = input_val;
            end
            default: begin
                addr_to_rom = addr_to_rom;
                data_from_rom = data_from_rom;
                delayed = delayed;
                input_val = input_val;
                to_avg = to_avg;
                val = val;
                output_val = output_val;
                ii = ii;
                end
        endcase
    end 

endmodule

您的组合 always 块中有 6 个状态,但您只在其中的 3 个中分配给 delayed。这意味着您想要保留状态,这会推断出闩锁。您应该确保 delayed 在所有状态(以及 if/else 的所有分支中,如果适用。

都被分配了一些值

此外,您的敏感度列表不完整。您可能想要更改:

always @(state_reg) begin 

至:

always @* begin 

@* 是隐式敏感列表,每当赋值的 RHS 上的任何信号发生变化时,它都会触发 always 块。

我注意到您使用了一种编码风格,即默认分配 state_next = state_reg 位于 always 块的最顶部。这使得 state_next 在未明确分配的情况下始终具有合法的驱动程序。这对于其他组合信号也是必需的。否则,闩锁推断。此外,信号 data_from_rom,我假设它是模块 rom_data 的输出,具有多个驱动程序。

您必须了解状态机的编程方式。通常状态是使用 flop 计算的,最终分配是组合的。反之亦然。因此你有问题。像下面这样的东西应该适合你。对不起,我没有测试它。代码需要使用 non-blocking 赋值,除了计算中间值的地方。

    always @* 
        state_reg = state_next;

    always @(posedge clk, negedge reset_n) begin //posedge clk, reset_n
        if (reset_n == 'b0) begin //reset is active low
            state_next <= s0;
        end 
        else begin
          case (state_reg)
            S0: begin
              output_val <= 0;
              delayed <= 0; 
              i <= 0;
              ii <= 0;
            end
            s1 : begin
                if (ii>(size-2)) begin
                   ii <= 0;
                end else begin
                   addr_to_rom <= ii;
                end
                input_val <= input_val;
                delayed <= delayed; 
                state_next <= s2;
            end
            s2 : begin
                input_val <= data_from_rom;
                ii <= ii+1;
                state_next <= s3;
            end
            s3 : begin
                delayed <= input_val;
                state_next <= s4;
            end
            s4 : begin
                addr_to_rom <= ii;
                state_next <= s5;
            end
            s5 : begin
                input_val <= data_from_rom;
                state_next <= s6;
            end
            s6 : begin
                // calculating intermediate value, need blocking assignments here
                to_avg = input_val + delayed; //need blocking here
                val = (to_avg >> 1);    //need blocking here

                output_arr[ii-1] <= val; //indexing starts on [2]
                output_val <= val; 
                state_next <= s0; 
            end
        endcase
      end // else
    end // always