代码之家  ›  专栏  ›  技术社区  ›  evilpascal

Verilog/SystemVerilog中的推断锁存器

  •  1
  • evilpascal  · 技术社区  · 10 年前

    过程块中的语句按顺序执行,所以为什么块1、块2或块3中的任何一个都不推断锁存?

    module testing(
        input  logic a, b, c,
        output logic x, y, z, v
        );
    
        logic tmp_ref, tmp1, tmp2, tmp3;
    
        //reference
        always_comb begin: ref_block
            tmp_ref = a & b;
            x = tmp_ref ^ c;
        end
    
        always_comb begin: block1
            y = tmp1 ^ c;
            tmp1 = a & b;
        end
    
        always @(*) begin: block2
            tmp2 <= a & b;
            z = tmp2 ^ c;
        end
    
        always @(c) begin: block3
            tmp3 = a & b;
            v = tmp3 ^ c;
        end
    endmodule: testing
    

    在块1中,在tmp1的新值可用之前,使用块赋值计算y。

    在块2中,tmp2是使用非块赋值来计算的,该赋值应在总是块完成时延迟赋值。同时,z是使用分块赋值计算的,tmp2的新值尚不可用。

    在块3中,有一个不完整的灵敏度列表,仍然没有锁存器。

    以下是Quartus II 14.1的合成结果: enter image description here

    只有当我添加此块时,才会推断出锁存:

    //infers a latch
    always @(*) begin: block4
        if (c == 1'b1) begin
            tmp4 = a & b;
            w = tmp4 ^ c;
        end
    end
    

    有人能解释一下为什么不完整的敏感度列表或在更新值之前使用变量不能推断组合块中的锁存器吗?

    1 回复  |  直到 10 年前
        1
  •  4
  •   Morgan    10 年前

    组合块中使用的赋值类型不会影响合成。非阻塞的使用( <= )可能导致RTL(预合成)到门(后合成)模拟器失配。

    敏感度列表也是如此,合成将给出自动生成或完整列表的行为。

    在计时过程中( @(posedge clk) )使用非阻塞( <= )以获得触发器的模拟行为。可以使用阻塞( = )以及在计时过程中使用组合代码,但混合样式被认为是一种糟糕的编码实践。组合部件代码只需移动到单独的组合块( always @* ).

    锁存器是一个基本的存储元件,如果电路不需要内存,那么它将不会被推断出来。

    例如:

    always @* begin: 
        v = (a & b) ^ c;
    end
    

    v 完全由输入定义,不涉及内存。相比之下:

    always @* begin
      if (c == 1'b1) begin
        w = (a & b) ^ c;
      end
    end
    

    什么时候 c 为0,必须保持其值,因此推断为锁存。

    值得注意的是,虽然锁存器并不坏,但必须注意打开和关闭的时间,以确保它们捕获正确的数据。因此,推断出的锁存器通常被认为是坏的,并且是由于编码不良。

    SystemVerilog具有以下语法,用于在语义上暗示设计意图:

    always_latch begin
      if (c == 1'b1) begin
        w = (a & b) ^ c;
      end
    end