Verilog:如何实例化模块

问题描述 投票:13回答:2

如果我有一个Verilog模块'top'和一个verilog模块'子组件',我如何在顶部实例化子组件?

最佳:

module top(
   input        clk,
   input        rst_n,
   input        enable,
   input  [9:0] data_rx_1,
   input  [9:0] data_rx_2,
   output [9:0] data_tx_2
);

子:

module subcomponent(
   input        clk,
   input        rst_n,
   input  [9:0] data_rx,
   output [9:0] data_tx
);

注意 这是一个通用的问题,不断出现,它遵循self-answer格式。鼓励添加答案和更新。

verilog system-verilog
2个回答
38
投票

SystemVerilog IEEE Std 1800-2012的第23.3.2节通常都涵盖了这一点。

最简单的方法是在top的main部分实例化,创建一个命名实例并按顺序连接端口:

module top(
   input        clk,
   input        rst_n,
   input        enable,
   input  [9:0] data_rx_1,
   input  [9:0] data_rx_2,
   output [9:0] data_tx_2
);

subcomponent subcomponent_instance_name (
  clk, rst_n, data_rx_1, data_tx ); 

endmodule

这在SystemVerilog IEEE Std 1800-2012的第23.3.2.1节中描述。

这有一些缺点,特别是关于子组件代码的端口顺序。这里简单的重构可以打破连接或改变行为。例如,如果其他人修复了一个错误并因某种原因重新排序了端口,请切换clk并重置顺序。您的编译器不会出现连接问题,但无法按预期工作。

module subcomponent(
  input        rst_n,       
  input        clk,
  ...

因此,建议使用命名端口进行连接,这也有助于跟踪代码中线路的连接。

module top(
   input        clk,
   input        rst_n,
   input        enable,
   input  [9:0] data_rx_1,
   input  [9:0] data_rx_2,
   output [9:0] data_tx_2
);

subcomponent subcomponent_instance_name (
  .clk(clk), .rst_n(rst_n), .data_rx(data_rx_1), .data_tx(data_tx) ); 

endmodule

这在SystemVerilog IEEE Std 1800-2012的第23.3.2.2节中描述。

为每个端口提供自己的行并正确缩进会增加可读性和代码质量。

subcomponent subcomponent_instance_name (
  .clk      ( clk       ), // input
  .rst_n    ( rst_n     ), // input
  .data_rx  ( data_rx_1 ), // input  [9:0]
  .data_tx  ( data_tx   )  // output [9:0]
);

到目前为止,所有已建立的连接都重复使用输入和输出到子模块,并且没有创建连接线。如果我们要将输出从一个组件转移到另一个组件,会发生什么:

clk_gen( 
  .clk      ( clk_sub   ), // output
  .en       ( enable    )  // input

subcomponent subcomponent_instance_name (
  .clk      ( clk_sub   ), // input
  .rst_n    ( rst_n     ), // input 
  .data_rx  ( data_rx_1 ), // input  [9:0]
  .data_tx  ( data_tx   )  // output [9:0]
);

这个名义上用作clk_sub的电线是自动创建的,存在依赖于此的危险。它默认只会创建1位线。这是一个问题的例子是数据:

请注意,第二个组件的实例名称已更改

subcomponent subcomponent_instance_name (
  .clk      ( clk_sub   ), // input
  .rst_n    ( rst_n     ), // input 
  .data_rx  ( data_rx_1 ), // input  [9:0]
  .data_tx  ( data_temp )  // output [9:0]
);
subcomponent subcomponent_instance_name2 (
  .clk      ( clk_sub   ), // input
  .rst_n    ( rst_n     ), // input 
  .data_rx  ( data_temp ), // input  [9:0]
  .data_tx  ( data_tx   )  // output [9:0]
);

上面代码的问题是data_temp只有1位宽,会有关于端口宽度不匹配的编译警告。需要创建连接线并指定宽度。我建议明确写出所有连接线。

wire [9:0] data_temp
subcomponent subcomponent_instance_name (
  .clk      ( clk_sub   ), // input
  .rst_n    ( rst_n     ), // input 
  .data_rx  ( data_rx_1 ), // input  [9:0]
  .data_tx  ( data_temp )  // output [9:0]
);
subcomponent subcomponent_instance_name2 (
  .clk      ( clk_sub   ), // input
  .rst_n    ( rst_n     ), // input 
  .data_rx  ( data_temp ), // input  [9:0]
  .data_tx  ( data_tx   )  // output [9:0]
);

移动到SystemVerilog有一些技巧可以节省键入一些字符。我相信它们会妨碍代码的可读性,并且会使查找错误变得更加困难。

使用没有括号的.port连接到同名的wire / reg。这看起来很整洁,尤其是在大量clk和复位时,但在某些级别,您可能会生成不同的时钟或复位,或者您实际上不希望连接到相同名称但已修改的信号,这可能会导致布线错误对眼睛不明显。

module top(
   input        clk,
   input        rst_n,
   input        enable,
   input  [9:0] data_rx_1,
   input  [9:0] data_rx_2,
   output [9:0] data_tx_2
);

subcomponent subcomponent_instance_name (
  .clk,                    // input **Auto connect**
  .rst_n,                  // input **Auto connect**
  .data_rx  ( data_rx_1 ), // input  [9:0]
  .data_tx  ( data_tx   )  // output [9:0]
);

endmodule

这在SystemVerilog IEEE Std 1800-2012的第23.3.2.3节中描述。

我认为另一个比上面更糟糕的技巧是.*将未提及的端口连接到同一线的信号。我认为这在生产代码中非常危险。如果新端口名称在实例化级别中具有计数器部分,则新端口已添加且丢失或者可能意外连接时,它们并不明显,它们将自动连接并且不会生成警告。

subcomponent subcomponent_instance_name (
  .*,                      // **Auto connect**
  .data_rx  ( data_rx_1 ), // input  [9:0]
  .data_tx  ( data_tx   )  // output [9:0]
);

这在SystemVerilog IEEE Std 1800-2012的第23.3.2.4节中描述。


3
投票

一定要检查verilog模式,尤其是verilog-auto。 http://www.veripool.org/wiki/verilog-mode/这是emacs的verilog模式,但是例如vi(m?)存在插件。

可以使用AUTOINST自动实例化。使用M-x verilog-auto扩展注释,然后可以手动编辑。

subcomponent subcomponent_instance_name(/*AUTOINST*/);

扩展

subcomponent subcomponent_instance_name (/*AUTOINST*/
  //Inputs
  .clk,         (clk)           
  .rst_n,       (rst_n)
  .data_rx      (data_rx_1[9:0]),
  //Outputs
  .data_tx      (data_tx[9:0])
);

隐式线可以使用/*AUTOWIRE*/自动化。查看链接以获取更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.