【问题标题】:How to reuse multiple always blocks in Verilog如何在 Verilog 中重用多个 always 块
【发布时间】:2015-12-10 12:25:47
【问题描述】:

下面是总是块代码。

我需要 11 次相同的代码,具有相同的功能但使用不同的变量。那么如何复用代码呢?

  always @(posedge tconClk or negedge tconRst_n)
  begin
    if(~tconRst_n)
    begin
      pulse_cnt <= 0;
      pulse_start = 0;
      start_written = 0;
      pulse_width <= 'h271;
    end
    else if(~pulse_rst)
    begin
      pulse_cnt <= 0;
      pulse_start = 0;
    end
    else
    begin
      if(start_signal)
      begin
//        start_written = 0;
        pulse_width <= (pulse_start) ? pulse_width : START_PW;
        pulse_start = 1;
      end
      pulse_cnt <= (pulse_start) ? (pulse_cnt + 1) : pulse_cnt;
    end
  end

命名模式-

  • tconClktconRst_n 很常见,
  • pulse_cnt0, pulse_cnt110,
  • pulse_width0, pulse_width110,
  • pulse_start[0:10](数组),
  • start_written[0:10](数组),
  • pulse_rst[0:10](数组),
  • start_signal[0:10](数组),
  • START_PW(无模式,每 11 个始终块的名称不同)

注意-

  1. 定义宏不起作用,因为此代码包含许多 verilog 标记。

  2. 我无法制作代码的模块,因为always块中使用的信号也用于代码的其他部分。因此,如果我制作模块,那么我将无法确保与模块进行正确的注册或电线连接。 (就像一个模块的输出端口必须是一根线,但相同的信号已被用作其他部分代码的reg)

【问题讨论】:

  • 我不知道为什么你不能为此使用宏。您可以定义包含许多标记的多行宏,所以我不确定您为什么认为您不能。
  • @Unn :我已经尝试过,通过带参数的多行宏,但我得到了编译错误。因此,如果可能的话,我请求您将其发布为答案。
  • 我不明白为什么这不能是一个模块。你有没有尝试过?驱动带有模块输出的 reg 很好。
  • 宏、模块或两者的组合都可以工作。你能举一些例子来说明其他变量名是什么吗?有命名模式吗?例如,所有组都有相同的后缀信号(例如:_cnt,_start,_width),只有前缀(pulse)发生变化。
  • Emacs verilog 模式 AUTO_TEMPLATE 来拯救。我现在没有时间为您的案例编写适当的模板,但这里是文档的链接:veripool.org/projects/verilog-mode/wiki/Faq

标签: verilog


【解决方案1】:

您可以使用 emacs 脚本verilog-mode 将 RTL 封装在一个模块中并利用 AUTO_TEMPLATE。然后在(或一批)emacs中执行verilog-batch-auto,如下所示(未测试):

/* PulseModule AUTO_TEMPLATE "\([0-9]+\)$" (
     .pulse_cnt(pulse_cnt@),
     .pulse_width(pulse_width@),
     .pulse_start(pulse_start[@]),
     .start_written(start_written[@]),
     .pulse_rst(pulse_rst[@]),
     .start_signal(start_signal[@]),
     .tconClk(tconClk),
     .tconRst_n(tconRst_n)
    );
*/
PulseModule pm_0 (/*AUTOINST*/ .start_pulse_width(START_PW) );
PulseModule pm_1 (/*AUTOINST*/ .start_pulse_width(OTHER_START_PW) );
...
PulseModule pm_10 (/*AUTOINST*/ .start_pulse_width(SOME_OTHER_START_PW) );

还有各种嵌入式代码(如Perl的EP3、Ruby的eRuby/ruby_it、Python的prepro等)可以生成想要的代码。

SystemVerilog 增强了宏的功能。对您而言,`` 功能将使您的任务更轻松。请参阅IEEE Std 1800-2012 § 22.5.1 `define.

多行宏很难调试。尽管可以将您的 RTL 作为一个宏,但我强烈建议将它放在一个模块中并让宏实例化宏。以下内容(未测试):

`define PULSEMACRO(id,val) \
   PulseModule pm_``id( \
     .pulse_cnt(pulse_cnt``id), .pulse_width(pulse_width``id), \
     .pulse_start(pulse_start[id]), .start_written(start_written[id]), \
     .pulse_rst(pulse_rst[id]), .start_signal(start_signal[id]), \
     .start_pulse_width(val) \
     .tconClk(tconClk), .tconRst_n(tconRst_n) )

这个实例化如下。请注意,生成 for 循环将不起作用。在生成块之前评估宏。

`PULSEMACRO(0,START_PW);
`PULSEMACRO(1,OTHER_START_PW);
...
`PULSEMACRO(10,SOME_OTHER_START_PW);

SystemVerilog 还可以通过模块端口传递多维数组。因此,您可以将 reg [PULSE_CNT_WIDTH-1:0] pulse_cnt0,...,pulse_cnt10 重命名为 logic [PULSE_CNT_WIDTH-1:0] pulse_cnt [11]。通过这种转换,您可以使用生成循环。


或者,您可以将pulse_cnt 折叠成一个大总线reg [PULSE_CNT_WIDTH*11-1:0] pulse_cnt,然后使用位切片来索引pulse_cnt[PULSE_CNT_WIDTH*index +: PULSE_CNT_WIDTH]。位切片也与 Verilog 兼容。见What is `+:` and `-:`?Indexing vectors and arrays with +:

【讨论】:

    【解决方案2】:

    always 放入generate 语句中。您应该在 SO 上找到很多示例:例如,here。您仍然需要修改您的代码,这可能并不比修改它以进行模块实例化更容易。

    此时您的代码已损坏,因为pulse_rst 在时钟沿之前进行了测试,并且它不在敏感度列表中。你应该把它放在列表中,或者重新编码块。请注意,Verilog 中存在两个异步控件和一个时钟的问题;查找“带有异步设置和重置的verilog flops”,或者用不同的问题再次提问。

    【讨论】:

    • generate 语句要求在 always 块内操作数组。但是在我的代码中,我没有数组,只是功能类似,但并非总是块内的所有元素都是数组的形式。那么除了“生成”还有什么方法可以重用呢?在代码中,我需要检查 pulse_rst,但只能在时钟的 posedge 上。所以我不能把 pulse_rst 放在敏感列表中
    • pulse_rst:对此的测试需要在最终(时钟)分支中,以使其同步重置(即if(pulse_rst)...else if(start_signal)。剩下的问题的两个选项是模块和generate,都需要你修改你的代码。generate 可能更容易——声明一个新数组并从always 语句中分配给它,然后在另一个新的always 中分配给来自新数组元素的原始信号。
    【解决方案3】:

    我认为你仍然可以使用宏。将那些非公共变量更改为宏,例如将pulse_cnt 更改为`pulse_cnt。将它们放入一个文件中,并将其用作包含文件。

    例如你的代码,

    always @(...) 
    begin
      `pulse_cnt <= 0;
      // ...
    end
    

    将此模板放入一个名为例如my_always.v的文件中

    然后在您的其他文件/模块中重用代码,如下所示:

    `define pulse_cnt pulse_cnt0
    `include "my_always.v"
    `undef pulse_cnt
    
    `define pulse_cnt pulse_cnt1
    `include "my_always.v"
    `undef pulse_cnt
    
    //... and so on
    

    【讨论】:

    • 它产生了编译错误,因为在my_always.v文件中直接使用了always块。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 2014-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多