【问题标题】:Can Verilog variables be given local scope to an always block?可以将 Verilog 变量赋予始终块的本地范围吗?
【发布时间】:2014-09-17 05:36:00
【问题描述】:

我有时发现在时钟始终块内对“局部变量”使用阻塞分配很有用。这有助于减少重复代码。

为了避免在不同的 always 块中意外使用相同的变量(这对于模拟来说可能是不确定的),我想给它局部范围。有没有一种很好的综合方式来做到这一点?

类似:

module sum3(
  input            clk,
  input      [7:0] in1,
  input      [7:0] in2,
  input      [7:0] in3,
  output reg [7:0] result,
  output reg [7:0] result_p1);

  begin :sum
    reg [7:0] sum_temp; // local variable
    always @(posedge clk) begin
      sum_temp   = in1 + in2 + in3;
      result    <= sum_temp;
      result_p1 <= sum_temp + 1;
    end
  end

endmodule

(ModelSim 似乎对此没问题,但 Synplify 似乎不喜欢它。)

【问题讨论】:

  • 为其他人澄清:请注意,开始/结束块需要命名才能创建范围。

标签: scope verilog blocking nonblocking


【解决方案1】:

我不确定普通 Verilog 中的语义,但根据 SystemVerilog LRM 第 6.21 节:

变量声明应在程序块中的任何语句之前。

因此以下是 SystemVerilog 中的合法语法:

module sum3(
  input            clk,
  input      [7:0] in1,
  input      [7:0] in2,
  input      [7:0] in3,
  output reg [7:0] result,
  output reg [7:0] result_p1);

  always @(posedge clk) begin : sum
    reg [7:0] sum_temp; // local variable (scope limited to process)
    sum_temp   = in1 + in2 + in3;
    result    <= sum_temp;
    result_p1 <= sum_temp + 1;
  end

endmodule

请注意,我已将变量声明 sum_temp 移动到进程中,从而限制了范围并消除了对命名 sum 块的需要。这在 Modelsim 和 Riviera 上编译(EDA Playground 上的示例)。

如果您的工具不支持此语法,请提出错误!

【讨论】:

    【解决方案2】:

    标准的可合成方式是使用带有wire的连续赋值:

    module sum3(
      input        clk,
      input  [7:0] in1,
      input  [7:0] in2,
      input  [7:0] in3,
      output reg [7:0] result,
      output reg [7:0] result_p1);
    
        wire [7:0] sum_temp = in1 + in2 + in3;
        always @(posedge clk) begin
          result    <= sum_temp;
          result_p1 <= sum_temp + 1;
        end
    endmodule
    

    【讨论】:

    • 这适用于这个简单(和人为)的示例,但在更复杂的情况下,这可能会损害可读性(赋值最终远离变量的使用位置)。此外,在某些情况下,您可能希望使用“局部变量”的不同中间值。
    • @mksuth 我不会损害可读性。 assignments end up far away from where the variables are used:远是什么意思?这是您无需担心的布局器和路由器的工作。如果你想使用 different intermediate values 在 always 块中使用另一个 reg
    • @tod,我只是指代码的人类可读性。如果always 块占用了数百行代码,那么将wire 用作“中间变量”可能会导致赋值远离(在代码中)wire 在内部实际使用的位置always 块。在我看来,在代码中将变量的赋值和变量的使用组合在一起,代码的可读性更高。
    • 组合在一起:只要可行。顺便说一句,一个always 块中的数百行代码 是问题所在。你为什么不在合适的地方把它分成多个总是块?你也可以使用循环...
    • @tod:另外,我相信这会污染模块命名空间,如果你想要像“i”这样的临时变量的简单名称(想想数组下标),这将是一个问题。
    【解决方案3】:

    尽管有共同的指导方针,但在时钟始终块内使用阻塞分配是可以的,并且有时正如你提到的那样有用。见这里:https://stackoverflow.com/a/4774450/1383356

    但是,某些工具可能不支持在 begin-end 块内定义的局部变量。

    或者,您可以尝试将 always 块的部分或全部主体放在任务中:

    task SUM_TASK();
      reg [7:0] sum_temp; // local variable
      sum_temp   = in1 + in2 + in3;
      result    <= sum_temp;
      result_p1 <= sum_temp + 1;
    endtask
    
    always @(posedge clk) begin
      SUM_TASK();
    end
    

    Verilog 任务可以访问全局变量和本地变量。此外,它们可以包含非阻塞分配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-01
      • 1970-01-01
      • 2013-06-05
      • 2013-02-13
      • 2022-06-12
      • 1970-01-01
      相关资源
      最近更新 更多