Verilog:如何实例化模块
如果我有一个Verilog模块“top”和一个Verilog模块“subcomponent”,我如何在top中实例化subcomponent 顶部: 子组件:Verilog:如何实例化模块,verilog,system-verilog,Verilog,System Verilog,如果我有一个Verilog模块“top”和一个Verilog模块“subcomponent”,我如何在top中实例化subcomponent 顶部: 子组件: module subcomponent( input clk, input rst_n, input [9:0] data_rx, output [9:0] data_tx ); 注意 这是一个经常出现的一般性问题,它遵循着这个格式。鼓励添加答案和更新。本指南第23.3.2节一般介绍
module subcomponent(
input clk,
input rst_n,
input [9:0] data_rx,
output [9:0] data_tx
);
注意这是一个经常出现的一般性问题,它遵循着这个格式。鼓励添加答案和更新。本指南第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
本规范第23.3.2.1节对此进行了说明
这有一些缺点,特别是关于子组件代码的端口顺序。这里简单的重构可以破坏连接或改变行为。例如,如果其他人修复了一个bug,并出于某种原因对端口重新排序,请切换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
本规范第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]
);
上述代码的问题是,数据_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,有一些技巧可以避免键入少量字符。我相信它们会阻碍代码的可读性,并使查找bug变得更加困难
使用不带括号的.port
连接到同名的导线/reg。这看起来很整洁,尤其是在大量时钟和复位的情况下,但在某些级别上,您可能会生成不同的时钟或复位,或者您实际上不希望连接到相同名称但经过修改的信号,这可能会导致肉眼看不到的接线错误
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
本规范第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]
);
这在的第23.3.2.4节中有描述。请务必检查verilog模式,尤其是verilog auto。这是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*/
实现自动化。查看链接了解更多信息。答案中没有提到的一件事(实际上问题中也没有提到)是如何使用参数实例化模块。我总是很难记住顺序和语法,因此:
#(.parameter_name(parameter_value),…)(.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));
我在标准中找不到的一条信息(我正在查看一个旧版本)是关于具有空端口列表的实例的:括号是否应该在
subcomponent subcomponent_instance_name()中代码>或省略,如子组件子组件\u实例\u名称代码>?或者这应该是一个单独的问题?@FriendFX为什么会有一个端口列表为空的模块?早期版本的工具使用需要括号()但是现代工具很可能只处理代码>示例是芯片的Verilog网络列表,这些芯片上有块实例,但块实例上没有任何逻辑端口,例如去耦电容器或芯片的徽标,它们对功能没有贡献。通过反复试验,我发现旧的工具确实不能只接受代码>和要求()代码>。我正在寻找一个明确的参考为这个案件虽然。你的链接已被打破。你知道标准的另一个托管地吗?@gobernador更新了链接,我想你必须注册,但仍然可以免费使用。
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));