Verilog 模块
一个module
是一个实现特定功能的 Verilog 代码块。模块可以嵌入到其他模块中,更高级别的模块可以使用它们的输入和输出端口与其更低级别的模块进行通信。
语法
一个模块 应包含在 module
内 和 endmodule
关键词。模块名称应紧跟在 module
之后 关键字和可选的端口列表也可以声明。请注意,端口声明列表中声明的端口不能在模块主体内重新声明。
module <name> ([port_list]);
// Contents of the module
endmodule
// A module can have an empty portlist
module name;
// Contents of the module
endmodule
所有变量声明、数据流语句、函数或任务以及低级模块实例(如果有)都必须在 module
中定义 和 endmodule
关键词。同一个文件中可以有多个不同名称的模块,可以按任意顺序定义。
示例
<无脚本>模块 dff 代表一个 D 触发器,它具有三个输入端口 d、clk、rstn 和一个输出端口 q。该模块的内容描述了 D 触发器在不同输入组合下的行为方式。在这里,如果 rstn 为高电平,则输入 d 始终在时钟的上升沿分配给输出 q,因为它是低电平有效复位。
// Module called "dff" has 3 inputs and 1 output port
module dff ( input d,
input clk,
input rstn,
output reg q);
// Contents of the module
always @ (posedge clk) begin
if (!rstn)
q <= 0;
else
q <= d;
end
endmodule
硬件示意图
该模块在综合过程中会被转换成下面的数字电路。
<无脚本>请注意,您不能在模块之外编写任何代码!
模块的用途是什么?
模块代表实现某些行为特征的设计单元,并将在综合过程中转换为数字电路。可以为模块提供任何输入组合,它将提供相应的输出。这允许相同的 module 被重用以形成更大的模块,实现更复杂的硬件。
例如,上图的DFF可以链接起来组成一个移位寄存器。
module shift_reg ( input d,
input clk,
input rstn,
output q);
wire [2:0] q_net;
dff u0 (.d(d), .clk(clk), .rstn(rstn), .q(q_net[0]));
dff u1 (.d(q_net[0]), .clk(clk), .rstn(rstn), .q(q_net[1]));
dff u2 (.d(q_net[1]), .clk(clk), .rstn(rstn), .q(q_net[2]));
dff u3 (.d(q_net[2]), .clk(clk), .rstn(rstn), .q(q));
endmodule
硬件示意图
请注意,dff 实例是通过 Verilog RTL 模块描述的线连接在一起的。
<无脚本>与其从较小的块构建更大的设计块,相反也可以这样做。考虑将一个简单的 GPU 引擎分解为更小的组件,以便每个组件都可以表示为实现特定功能的模块。下面显示的 GPU 引擎可以分为五个不同的子块,每个子块执行特定的功能。总线接口单元从外部获取数据到设计中,由另一个单元处理以提取指令。其他单位下线处理前单位提供的数据。
<无脚本>
每个子块可以表示为一个module
具有一定的输入和输出信号集,用于与其他模块通信,每个子块可以根据需要进一步细分为更细的块。
什么是顶级模块?
一个顶级 模块是一个 包含 所有其他模块。顶级模块不在任何其他模块中实例化。
例如,设计模块通常在顶级测试平台模块中进行实例化,以便可以通过提供输入激励来运行仿真。但是,testbench 没有在任何其他模块中实例化,因为它是一个封装其他所有内容的块,因此是 顶级模块 .
设计顶层
下面显示的设计代码有一个称为设计的顶级模块。这是因为它包含完成设计所需的所有其他子模块。子模块可以有更多的嵌套子模块,如 mod1 中的 mod3 和 mod2 中的 mod4。总之,当 mod1 和 mod2 被实例化时,所有这些都包含在顶层模块中。所以这使得 设计 完整,是设计的顶层模块。
//---------------------------------
// Design code
//---------------------------------
module mod3 ( [port_list] );
reg c;
// Design code
endmodule
module mod4 ( [port_list] );
wire a;
// Design code
endmodule
module mod1 ( [port_list] ); // This module called "mod1" contains two instances
wire y;
mod3 mod_inst1 ( ... ); // First instance is of module called "mod3" with name "mod_inst1"
mod3 mod_inst2 ( ... ); // Second instance is also of module "mod3" with name "mod_inst2"
endmodule
module mod2 ( [port_list] ); // This module called "mod2" contains two instances
mod4 mod_inst1 ( ... ); // First instance is of module called "mod4" with name "mod_inst1"
mod4 mod_inst2 ( ... ); // Second instance is also of module "mod4" with name "mod_inst2"
endmodule
// Top-level module
module design ( [port_list]); // From design perspective, this is the top-level module
wire _net;
mod1 mod_inst1 ( ... ); // since it contains all other modules and sub-modules
mod2 mod_inst2 ( ... );
endmodule
测试台顶层
测试台模块包含用于检查设计功能的激励,主要用于使用仿真工具进行功能验证。因此,该设计在测试平台模块内被实例化并称为 d0。从模拟器的角度来看,testbench 是最顶层的模块。
//-----------------------------------------------------------
// Testbench code
// From simulation perspective, this is the top-level module
// because 'design' is instantiated within this module
//-----------------------------------------------------------
module testbench;
design d0 ( [port_list_connections] );
// Rest of the testbench code
endmodule
分层名称
当模块可以在另一个内部实例化时,就会形成一种层次结构,因此顶层模块称为 root .由于给定模块中的每个较低模块实例都需要具有不同的标识符名称,因此在访问信号时不会有任何歧义。分层名称由这些标识符的列表构成,这些标识符由点 .
分隔 对于层次结构的每个级别。任何信号都可以在任何模块中使用该特定信号的分层路径访问。
// Take the example shown above in top level modules
design.mod_inst1 // Access to module instance mod_inst1
design.mod_inst1.y // Access signal "y" inside mod_inst1
design.mod_inst2.mod_inst2.a // Access signal "a" within mod4 module
testbench.d0._net; // Top level signal _net within design module accessed from testbench
Verilog