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

posted @ 2017-10-05 09:43  米兰de小铁匠  阅读(4767)  评论(0编辑  收藏  举报