【问题标题】:Is there a way to define something like a C struct in Verilog有没有办法在 Verilog 中定义类似 C 结构的东西
【发布时间】:2014-12-16 18:23:35
【问题描述】:

我有一个项目,用 Verilog(重要的是不是 SystemVerilog)编写的,由于在设计的不同部分之间传递的信号数量,它变得有点难以管理。由于我有几个模块都需要相同的信号,因此我正在考虑尝试将它们合并到数量较少的命名对象中。问题是如何去做。

假设这是我人为的例子:

module mymodule(sig_a_in, sig_b_in, sig_c_in, sig_d_in, sig_e_in,
                sig_a_out, sig_b_out, sig_c_out, sig_d_out, sig_e_out);

  input wire sig_a_in, sig_b_in, sig_c_in;
  input wire [5  : 0] sig_d_in;
  input wire [31 : 0] sig_e_in;
  output reg sig_a_out, sig_b_out, sig_c_out;
  output reg [5  : 0] sig_d_out;
  output reg [31 : 0] sig_e_out;
endmodule

在我看来,重要的是我可以按名称引用信号的可读性。但是,我不想将它们全部单独传递给每个模块。同样,我只在这个项目中使用 Verilog,所以 SystemVerilog 构造是不可能的。

我的第一个想法是我将它们组合到一个总线中,然后使用定义的名称来引用各个电线。然而,这有点笨拙,尤其是当您将其他总线添加到混音中时。这在我设计的示例中非常简单,因为信号具有明显的隐含顺序,但在现实生活中却没有。

`define SIGNAL_BUS_WIDTH 41
`define A 0
`define B 1
`define C 2
`define D 3
`define E 9

module mymodule(signal_bus_in, signal_bus_out);

  input wire [`SIGNAL_BUS_WIDTH-1 : 0] signal_bus_in;
  output reg [`SIGNAL_BUS_WIDTH-1 : 0] signal_bus_out;

  // reference a
  signal_bus_in[`A]
  // reference d?  Not good when names don't have an obvious order
  signal_bus_in[`E-1 : `D]
endmodule

最后,除了所有这些之外,工具链还必须能够区分结构中的哪些线被模块使用,并且只合成这些线。并非所有模块都使用所有电线,所以我想避免有多余的未使用路径。我认为这些工具应该足够聪明才能做到这一点,即使在我上面的巴士示例中也是如此,但我并不完全确定。

有没有一种在 Verilog 中获得我想要的东西的好方法?

【问题讨论】:

  • 那是 SystemVerilog 的。我使用的是 Verilog,而不是 SystemVerilog。
  • Verilog 在处理复杂数据结构时非常有限。这就是为什么它在 Verilog-2005 之后被 IEEE 替换为 SystemVerilog。

标签: struct verilog hdl


【解决方案1】:

您总是可以通过使用宏来定义每个信号的范围而不是端点来进一步扩展您的想法:

`define WIDTH 41
`define sigA 0:0
`define sigB 1:1
`define sigC 2:2
`define sigD 8:3
`define sigE 40:9

module mymodule(signal_bus_in, signal_bus_out);

  input wire [`WIDTH-1 : 0] signal_bus_in;
  output reg [`WIDTH-1 : 0] signal_bus_out;

  ...
  // signal a
  signal_bus_in[`sigA];
  // signal d
  signal_bus_in[`sigD];
  ...

当然,这不像 SystemVerilog 打包结构那么简单(这就是它们存在的原因!),但它可以满足您的需求。此外,这也为您的线路添加了顺序,但我没有看到不会这样做的结构;甚至结构也会为您的信号添加顺序。但是,只要您使用宏,那么顺序并不重要,除非您定义宏。

任何好的综合工具都应该能够丢弃任何不驱动任何东西或不被任何东西驱动的端口或电线,所以除非你必须明确告诉它由于某种原因要忽略哪些线,否则你不应该担心它为未使用的模块引脚合成额外空间。

【讨论】:

  • 我不担心宏会在行中添加顺序。我只是不想知道哪个是下一个命名信号才能找到最高有效位。你的建议完成了这一点,所以它应该足以满足我的目的。
【解决方案2】:

Verilog 没有结构。 IMO 将所有信号组合成一个长向量(或者你称之为总线)是你最好的选择。但是,您可以稍微改进一下宏:

`define SIGNAL_BUS_WIDTH 41
`define A 0:0
`define B 1:1
`define C 2:2
`define D 8:3
`define E 40:9

// reference a
signal_bus_in[`A]
// reference d  
signal_bus_in[`D]
// reference e  
signal_bus_in[`E]

大多数综合工具不会为未连接的电线创建额外的逻辑,并将它们视为无关紧要。

【讨论】:

    【解决方案3】:

    为避免过度依赖预处理器,您可以尝试使用localparamfunction 声明来模拟结构。下面是一个“mybus”结构的模型,它有四个字段,从 A 到 D,大小不一,用来说明这个想法。

    你可以把这些支持的参数和函数放到一个文件中,你include只在需要构建和解构这种总线的各个模块中。这也许可以让您使用较短的名称而不必担心冲突。

    module test ;
    
    
    // Boilerplate structure size definitions -- you could automatically generate these
    // with a simple script and put them into an include file.
    
    localparam mybus_a_size = 4;
    localparam mybus_a_offset = 0;
    
    localparam mybus_b_size = 8;
    localparam mybus_b_offset = mybus_a_offset + mybus_a_size;
    
    localparam mybus_c_size = 4;
    localparam mybus_c_offset = mybus_b_offset + mybus_b_size;
    
    localparam mybus_d_size = 6;
    localparam mybus_d_offset = mybus_c_offset + mybus_c_size;
    
    localparam mybus_size = mybus_a_size + mybus_b_size + mybus_c_size + mybus_d_size;
    
    
    // accessor functions, i.e., instead of bus.a you write mybus_a(bus)
    
    function [mybus_a_size-1:0] mybus_a (input [mybus_size-1:0] in);
      mybus_a = in[mybus_a_size + mybus_a_offset - 1 : mybus_a_offset];
    endfunction
    
    function [mybus_b_size-1:0] mybus_b (input [mybus_size-1:0] in);
      mybus_b = in[mybus_b_size + mybus_b_offset - 1 : mybus_b_offset];
    endfunction
    
    function [mybus_c_size-1:0] mybus_c (input [mybus_size-1:0] in);
      mybus_c = in[mybus_c_size + mybus_c_offset - 1 : mybus_c_offset];
    endfunction
    
    function [mybus_d_size-1:0] mybus_d (input [mybus_size-1:0] in);
      mybus_d = in[mybus_d_size + mybus_d_offset - 1 : mybus_d_offset];
    endfunction
    
    
    // constructor function -- build a mybus out of its components
    
    function [mybus_size-1:0] make_mybus(input [mybus_a_size-1:0] a,
                                          input [mybus_b_size-1:0] b,
                                          input [mybus_c_size-1:0] c,
                                          input [mybus_d_size-1:0] d);
      make_mybus = {d,c,b,a};
    endfunction
    
    
    // example of using this stuff
    
    reg [mybus_size - 1 : 0] bus;
    
    initial begin
      bus = make_mybus(1,2,3,4);
      $display("Hello, my bus is { a=%b, b=%b, c=%b, d=%b }", mybus_a(bus), mybus_b(bus), mybus_c(bus), mybus_d(bus));
    end
    
    endmodule
    

    这个模型可能是一个很好的起点。一些明显的改进是从一个简单的脚本自动生成所有这些样板,并添加额外的构造函数,如 C++ 中的“setters”,即

    set_mybus_a(mybus, 5)   // set mybus.a = 5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-11
      • 1970-01-01
      • 2014-09-05
      • 2021-11-01
      相关资源
      最近更新 更多