Verilog:如何实例化一个模块
如果我有一个Verilog模块“top”和一个verilog模块“subcomponent”,我该如何实例化子组件?
最佳:
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 );
注意
这被写成一个不断出现的通用问题,它遵循自我回答的格式。 鼓励添加答案和更新。
SystemVerilog IEEE Std 1800-2012的第23.3.2部分涵盖了这一点。
最简单的方法是在顶层的主要部分实例化,创build一个命名实例并按顺序连接端口:
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节中描述。
这有几个缺点,特别是关于子组件代码的端口顺序。 这里简单的重构可能会破坏连接或改变行为。 例如,如果其他人修复一个错误,并由于某种原因重新sorting这些端口,则切换时钟和重置顺序。 你的编译器将没有连接问题,但不能按预期工作。
module subcomponent( input rst_n, input clk, ...
因此build议使用命名端口进行连接,这也有助于跟踪代码中的连线。
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] );
到目前为止,所有已经build立的连接都重新使用input和输出到子模块,并且没有连接线被创build。 如果我们要从一个组件到另一个组件的输出会发生什么?
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的电线自动创build,依靠这个有一个危险。 它只会默认创build一个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位宽,会有一个关于端口宽度不匹配的编译警告。 需要创build连接线并指定宽度。 我会build议所有的连接线明确写出来。
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有一些技巧,可以节省inputless数字符。 我相信它们妨碍了代码的可读性,并且可以使其更难find错误。
使用没有括号的.port
连接到相同名称的wire / 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
这在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节中描述。
一定要看看verilog模式,尤其是verilog-auto。 http://www.veripool.org/wiki/verilog-mode/这是emacs的verilog模式,但是例如vi(m?)存在插件。;
AUTOINST可以自动实例化。 用Mx 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*/
自动执行。 查看链接了解更多信息。