在Verilog程序中使用连续赋值?

时间:2014-05-15 19:36:28

标签: verilog fpga system-verilog

在Verilog程序中使用连续赋值是否可行和/或有用?例如,是否有任何理由将assign置于always块内?

例如这段代码:

always @(*) 
begin 
  assign data_in = Data;
end

此外,是否可以使用这种方法生成顺序逻辑?

always @(posedge clk) 
begin 
  assign data_in = Data;
end

1 个答案:

答案 0 :(得分:6)

它被称为程序连续分配。在程序块中使用assignforce(及其对应的对应deassignrelease)。在程序块中到达行时,将创建新的连续分配过程。 assign可以应用于注册类型,例如regintegerrealforce可以应用于寄存器和网络(即wire s)。自1364-1995以来,它一直是LRM的一部分。

  • IEEE Std1364-1995§9.3
  • IEEE Std1364-2001§9.3
  • IEEE Std1364-2005§9.3
  • IEEE Std1800-2005§25.3
  • IEEE Std1800-2009§10.6
  • IEEE Std 1800-2012§10.6

大多数工具都可以合成程序性连续分配。然而,建议将其用于限制模拟块,测试台文件或修复RTL - 门功能不匹配的行为建模。

  • always @* assign data_in = Data;
    功能与
    always @* data_in = Data;

  • 相同
  • always @(posedge clk) assign data_in = Data;
    功能与:
    always @(posedge clk)
      enable = 1;
    always @*
      if (enable==1) data_in = Data;
  • 相同

程序连续分配的有效使用应适用于以下内容:

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_nset_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

以这种方式使用assign / deassign正在考虑在将来的IEEE 1800版本中进行折旧。 IEEE Std1800-2005§25.3,IEEE Std1800-2009§C.4.2和IEEE Std 1800-2012§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);
    
    • 解决方案(假设原始功能错误):

      always @(posedge clk)
        if (sel) reg2 <= func1(x,y,z); // Non-blocking assignment !!!
        else     reg2 <= func2(a,b,c);
      
    • 解决方案(假设原始功能正确):

      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);