Verilog:如何实例化模块

时间:2013-11-19 08:44:39

标签: verilog system-verilog

如果我有一个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格式。鼓励添加答案和更新。

3 个答案:

答案 0 :(得分:38)

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

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

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连接到同名的电汇/注册表。这看起来很整洁,尤其是在大量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节对此进行了描述。

答案 1 :(得分:3)

请务必查看verilog-mode,特别是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*/自动化。查看链接以获取更多信息。

答案 2 :(得分:1)

答案中没有提到的一件事(实际上也没有在问题中提出)是如何使用参数实例化模块。我总是很难记住顺序和语法,所以这里是:

<component_name> #(.parameter_name( parameter_value ), ... ) <instance_name>(.port_name( wire/reg_name ), ...)

因此,如果您有一个带有参数 N 的模块 fooBar,并且您想创建一个具有不同参数值的 fooBarInstance:

module fooBar #(parameter N = 8) (input [N-1:0] foo, output[N-1:0] bar)
endmodule

// Instantiate fooBar with N=12
fooBar #(.N(12)) fooBarInstance(.foo(fooWire), .bar(barReg));