Verilog中使用'include实现参数化设计
前段时间在FPGA上用Verilog写了一个多端口以太网的数据分发模块,因为每个网口需要独立的MAC地址和IP地址,为了便于后期修改,在设计中使用parameter来定义这些地址和数据总线的位宽等常量。
当时的做法是,顶层模块和子模块中都定义parameter型常数,在顶层模块引用子模块时,通过参数传递改变在被引用子模块中已定义的参数,实现在顶层模块统一管理参数的功能,代码如下
1 module top(); // 顶层模块 2 parameter eth1_ip_addr = {8'd192, 8'd168, 8'd100, 8'd1}; // 以太网1 IP地址 192.168.100.1 3 parameter eth2_ip_addr = {8'd192, 8'd168, 8'd100, 8'd2}; // 以太网2 IP地址 192.168.100.2 4 5 // 子模块1例化 6 sub1 7 #( .ip_addr(eth1_ip_addr) // 参数传递 8 ) 9 sub1_inst( ); //端口映射 10 11 // 子模块2例化 12 sub2 13 #( .ip_addr(eth2_ip_addr) // 参数传递 14 ) 15 sub2_inst( ); //端口映射
子模块1和2分别实现以太网1和2的收发功能,ip_addr为各自的本地IP地址,通过参数传递将eth1_ip_addr和eth2_ip_addr的值分别传递给两个子模块的ip_addr常数。
不过上述方法的缺点在于:
1. 当子模块的参数较多,并且要多次实例化时,代码会显得较为臃肿
2. 假如工程的层次有4层,某个参数只在第4层的模块使用到,为了实现将参数从顶层传递到第4层,第2层和第3层模块的参数列表中必须包含该参数。
解决上述问题有两种方法:
1. 使用defparam命令在顶层模块对子模块中的参数重定义,但是该方法同样存在一个问题:改变已经实例化后的模块中的参数,必须用英文小数点(.)表示层次逻辑关系,如下所示
1 module top; 2 reg clk; 3 reg [0:4] in1; 4 reg [0:9] in2; 5 wire [0:4] o1; 6 wire [0:9] o2; 7 // 子模块实例化 8 vdff m1 (o1, in1, clk); 9 vdff m2 (o2, in2, clk); 10 endmodule 11 // 子模块定义 12 module vdff (out, in, clk); 13 parameter size = 1, delay = 1; 14 input [0:size-1] in; 15 input clk; 16 output [0:size-1] out; 17 reg [0:size-1] out; 18 19 always @(posedge clk) 20 # delay out = in; 21 endmodule 22 // 参数重定义模块 23 module annotate; 24 defparam 25 top.m1.size = 5, // size参数的层次化表示 26 top.m1.delay = 10, 27 top.m2.size = 10, 28 top.m2.delay = 20; 29 endmodule
具体使用方法见http://www.cnblogs.com/hechengfei/p/4116667.html
2. 使用`inculude
预处理命令
最近在STM官网上找M95xxx系列的EEPROM资料时,看到该芯片的Verilog Testbench模块,如下图所示
M95XXX_Macro_Mux.v:定义M95xxx系列芯片的AC参数
M95XXX_Parameters.v:定义Memory大小、有效地址位数和Page大小等参数
M95xxx_Testbench.v:链接 M95xxx_Driver.v和M95xxx_Memory.v
M95xxx_Driver.v:模拟M95xxx_Memory.v文件基于SPI接口的读写行为
M95xxx_Memory.v:M95xxx EEPROM的行为级描述模型
在上述文件中,M95XXX_Macro_Mux.v和M95XXX_Parameters.v定义了全局参数,被其他文件通过’include命令包含到文件内。具体使用方法如下
M95XXX_Parameters.v 参数定义文件
1 `define MEM_ADDR_BITS 11 //memory address bits 2 `define PAGE_ADDR_BITS 6 //page address bits
M95xxx_Driver.v 驱动文件
`include "M95XXX_Parameters.v" reg[`MEM_ADDR_BITS-1:0] memory_address; reg[`PAGE_ADDR_BITS-1:0] page_address;
可以看到要调用参数文件中参数时,需要:
1. 使用'include
命令包含参数文件
2. 使用反引号+参数名的方式来调用该参数
STM MP95xxx系列EEPROM Verilog Testbench模型的链接地址:
https://gitee.com/hombeen/codes/y9rb0g7ej385sipqozvla95