gpt4 book ai didi

Verilog:如何实例化模块

转载 作者:行者123 更新时间:2023-12-03 21:04:59 26 4
gpt4 key购买 nike

如果我有一个 Verilog 模块“顶部”和一个 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。格式。鼓励添加答案和更新。

最佳答案

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 节中有所描述。 .

关于Verilog:如何实例化模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20066850/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com