1

程序块中的语句按顺序执行,那么为什么块 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

在 block1 中,在 tmp1 的新值可用之前使用阻塞分配计算 y。

在 block2 中,tmp2 是使用非阻塞赋值计算的,它应该在 always 块完成时推迟赋值。同时,z 是使用阻塞分配计算的,tmp2 的新值尚不可用。

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

这是 Quartus II 14.1 的综合结果: 在此处输入图像描述

只有当我添加这个块时,才会推断出一个锁存器:

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

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

4

1 回答 1

4

组合块中使用的赋值类型不会影响合成。使用非阻塞 ( <=) 可能会导致 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 w 必须保持其值,因此推断为锁存器。

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

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

always_latch begin
  if (c == 1'b1) begin
    w = (a & b) ^ c;
  end
end
于 2015-01-24T23:45:51.510 回答