它被称为程序连续分配。这是使用一个assign
or force
(及其相应的对应物deassign
and release
)在程序块内。当到达程序块中的行时,将创建一个新的连续分配过程。assign
可以应用于寄存器类型,例如reg
, integer
, and real
. force
可以应用于寄存器和网络(即wire
s)。自 1364 年至 1995 年以来,它一直是 LRM 的一部分。
- IEEE 标准 1364-1995 § 9.3
- IEEE 标准 1364-2001 § 9.3
- IEEE 标准 1364-2005 § 9.3
- IEEE 标准 1800-2005 § 25.3
- IEEE 标准 1800-2009 § 10.6
-
IEEE 标准 1800-2012 https://standards.ieee.org/findstds/standard/1800-2012.html § 10.6
大多数工具都可以综合程序连续分配。然而,建议限制使用模拟块的行为建模、测试台文件或修复 RTL 门功能不匹配。
程序连续赋值的有效使用应适用于以下情况:
always @(posedge clk or negedge rst_n, negedge set_n) begin
if (!rst_n) q <= 1'b0;
else if (!set_n) q <= 1'b1;
else q <= d;
end
它将合成一个具有异步设置和复位优先级的触发器。然而,在模拟中,如果以下情况,模型是不准确的:rst_n
and set_n
那么两者都低rst_n
走高。q
如果异步集仍处于启用状态,但敏感度列表中没有任何内容可触发,则应转到 1。这是 Verilog 的一个有据可查的问题。当与合成器的 translate off 关键字一起使用时,这是 RTL 中允许程序连续赋值的一种情况。这release
/deassign
允许以通常的方式分配寄存器/线路。
// translate_off
always @(rst_n or set_n)
if (rst_n && !set_n) force q = 1'b1;
else release q;
// translate_on
OR(当前有效但不鼓励)
// translate_off
always @(rst_n or set_n)
if (rst_n && !set_n) assign q = 1'b1;
else deassign q;
// translate_on
Using assign
/deassign
这种方式被认为在未来的 IEEE 1800 版本中被贬值。 IEEE 标准 1800-2005 § 25.3、IEEE 标准 1800-2009 § C.4.2 和IEEE 标准 1800-2012 https://standards.ieee.org/findstds/standard/1800-2012.html§ C.4.2 认识到assign
这种方式使用会导致混乱并且是错误的根源。使用force
/release
如果需要的话程序连续赋值。
在使用过程连续赋值的生成中(使用force
/release
) 仅应在绝对必要时使用。替代方法更可靠。
程序连续赋值的误用及解决方案:
-
组合逻辑开启reg
:
always @(sel)
if (sel) assign reg1 = func1(x,y,z);
else assign reg1 = func2(a,b,c);
-
解决方案:
always @* // <- IEEE Std 1364-2001 construct
if (sel) reg1 = func1(x,y,z);
else reg1 = func2(a,b,c);
-
组合逻辑开启wire
:
always @(sel)
if (sel) force wire1 = func1(x,y,z);
else force wire1 = func2(a,b,c);
-
解决方案:
assign wire1 = sel ? func1(x,y,z) : func2(a,b,c);
-
顺序逻辑:
always @(posedge clk)
if (sel) assign reg2 = func1(x,y,z);
else assign reg2 = func2(a,b,c);
-
解决方案 (assuming原来的功能是wrong):
always @(posedge clk)
if (sel) reg2 <= func1(x,y,z); // Non-blocking assignment !!!
else reg2 <= func2(a,b,c);
-
解决方案 (assuming原来的功能是correct):
reg flop_sel;
always @(posedge clk)
flop_sel <= sel; // Non-blocking assignment !!!
always @*
if (flop_sel) reg2 = func1(x,y,z); // Blocking assignment !!!
else reg2 = func2(a,b,c);