本文主要是介绍FPGA开发:模块 × 实例化,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
模块的结构
对于C语言,其基本单元为函数。与此类似,Verilog的基本设计单元称之为"模块"(block)。对于整个项目的设计思想就是模块套模块。
一个模块由两个部分组成:一部分描述接口,一部分描述逻辑功能。
每个Verilog模块包含4个部分:端口定义、IO说明、内部信号声明、功能定义。且位于module和endmodule之间,如下:
module block(a,b,c);input a,b; //模块的输入,不需要规定类型output wire c; //模块的输出,一定要规定类型wire d; //定义内部信号assign d=a|b; //组合逻辑输出assign c=d?a:b; //组合逻辑输出
endmodule
1、模块名及端口
模块的端口声明了模块的输入输出口,相当于C语言函数的参数和返回值。格式如下:
- module 模块名(端口名1,端口名2,...,端口名n);
如果将模块看作一个芯片,那么模块名就相当于芯片的名字(例如STM32F103C8T6),端口定义就相当于确定了这个芯片有哪些端口(引脚),而下面的IO声明就相当于规定引脚是输入还是输出。
2、IO声明
模块的端口可以是输入端口、输出端口和双向端口。
对于输入端口:
input [信号位宽-1:0] 端口名1;
input [信号位宽-1:0] 端口名2;
……
input [信号位宽-1:0] 端口名n;
对于输出端口:
output [信号位宽-1:0] 端口名1;
output [信号位宽-1:0] 端口名2;
……
output [信号位宽-1:0] 端口名n;
对于双向端口:
inout [信号位宽-1:0] 端口名1;
inout [信号位宽-1:0] 端口名2;
……
inout [信号位宽-1:0] 端口名n;
【注意】位宽可省略不写,此时就默认其位宽为1位。
【注意】对于信号位宽,N位宽就是指对应的端口由N根引脚组成。
3、内部信号声明
通常是声明wire和reg型的变量。
reg [位宽-1:0] R变量1,...,R变量n;
wire [位宽-1:0] W变量1,...,W变量n;
模块的实例化
模块实例化是将一个模块作为组件使用在另一个模块中。这类似于在编程中在A函数里调用一个B函数。通过实例化,可以实现将复杂的设计按功能分解为更小的、可复用的一个个模块。
实例化有以下两种方法:
1、端口名重映射
假设我们有两个模块:一个是已经定义好的A模块,另一个是B模块,如下面的代码所示,B模块实例化了A模块。
- A模块定义
module A(input wire [31:0] int1;input wire [31:0] int2;output wire [31:0] out;
);assign out = int1 + int2;
endmodule
- B模块定义
module B(input wire [31:0] a;input wire [31:0] b;output wire [31:0] sum;
);endmodule
- 实例化A模块
A u_A (.int1(a), // 将B模块的输入 a 连接到子模块A的 int1 端口.int2(b), // 将B模块的输入 b 连接到子模块A的 int2 端口.out(sum) // 将子模块A的输出 out 连接到B模块的输出 sum
);
在B模块中,我们实例化了A模块,并且对这个实例取了一个名字"u_A"。实例化之后,通过端口映射,将B模块的端口 a、b 和 sum 分别连接到子模块B的端口 int1、int2 和 out。
2、位置映射
module B(input wire [31:0] a,input wire [31:0] b,output wire [31:0] sum
);// 实例化 A 模块,使用位置映射A u_A (a, b, sum); // 依次将 a, b 和 sum 连接到子模块A的 in1, in2 和 out
endmodule
【注意】使用位置映射时,要特别注意端口的顺序必须与子模块的端口定义顺序一致,否则可能会导致错误的连接。
这篇关于FPGA开发:模块 × 实例化的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!