参数化建模
你没有过这样的经历:当你制作的FPGA板卡与整机调试时,为了验证技术指标,可能需要对代码进行微调,这就需要你出不同的版本。那么按一个小时生成一个版本的比特流文件,那么按8小时工作日来算,一天只能生成8个版本,你不加班谁加班……
虽然verilog的参数必须在编译时确定值。也就是说只能达到动态编译,固态运行,而非软件的动态编译,动态运行。
比如一个计数器,我们可以设置一个参数来指定它的计数周期(动态编译),但是这个计数周期在综合之后就是固定值了(固态运行),不能在运行的时候动态地改为另外一个值(除非电路综合时同时产生了多个计数器,这种情况不算真正意义上的动态运行,而且也达不到真正意义上的动态运行,因为不可能把所有可能的计数器都实现了备用,耗费资源而且没有实际意义)。
参数化建模需要达到的目的是:提高模块的通用性,只需要修改参数,不用修改其他代码就可以适用于不同的环境中。
那么参数化建模有几种方式呢:
`define
parameter
`ifdef
一、`define(宏替代)
`define 是编译器指令,功能是全局宏定义的文本代替。它类似于 C 语言中的 #define ,用法如下:
`define WORD_REG reg [31:0]
`WORD_REG reg32;
在使用`define 时,尽可能把所有的宏定义放在同一个头文件中,比如 “global_define.vh”,防止在不同文件中发生重定义的问题;
编译顺序有要求 file-order dependent,即必须确保使用前,宏定义有效,所以每个使用到宏定义的源文件必须包含这个头文件,对于这个问题,和 C++ 类似,头文件应该使用头文件保护符。
// global_define.vh head file
`ifndef GLOBAL_DEFINE_VH
`define MAX = 8
`define SIZE = 4
// ...
`endif
使用`define 需注意到的问题总结如下:
1.只有那些要求有全局作用域、并且在其他地方不会被修改的常量才用 define 来定义
2.对于那些只限于模块内的常量,不要使用 define
3.尽可能将所有的 define 都放在同一个文件中,然后在编译时先读取这个文件
4.不要使用 `undef
二、parameter(参数重定义)
先提一下localparam,它用来定义模块内部的、不能被其他模块修改的局部常量,概念类似于 C++ 中 class 的 protect 成员。需要注意的是parameter能被其他模块修改。localparam用的最多的地方是状态机的定义。
虽然 localparam 不能被外部模块修改,但是它可以用 parameter 来初始化。比如:
parameter N = 8;
localparam N1 = N - 1;
parameter重定义的方式:
比如模块 myreg
module myreg (q, d, clk, rst);
parameter Trst = 1,
Tclk = 1,
SIZE = 4;
// ...
endmodule
在上一层的模块中传递参数例化这个模块
module bad_warpper (q, d, clk, rst)
// legal parameter passing
myreg #(1, 1, 8) r1(.q(q), .d(d), .clk(clk), .rst(rst) );
// illegal parameter passing
// myreg #(,,8) r1(.q(q), .d(d), .clk(clk), .rst(rst) );
endmodule
也可以用下面这种方式(推荐),比如只想改变 SIZE 的值
myreg #(.SIZE(8)) r1(.q(q), .d(d), .clk(clk), .rst(rst) );
需要注意的是,最好不要使用defparam。
三、条件编译
Verilog 的条件编译和 C 也十分类似。条件编译一共有 5 个关键字,分别是:
`ifdef `else `elsif `endif `ifndef
条件编译在什么情况中使用呢?
1.选择一个模块的不同部分
2.选择不同的时序和结构
3.选择不同的仿真激励
例程代码:
//example1
`ifdef text_macro
// do something
`endif
// example2
`ifdef text_macro
// do something
`else
// do something
`endif
// example3
`ifdef text_macro
// do something
`elsif
// do something
`else
// do something
`endif
// example4
`ifndef text_macro
// do something
`else
// do something
`endif
条件编译是一个非常好的技术,它可以帮助我们更好的管理代码。
举个栗子,比如我们写了一个程序,在 debug 阶段,在程序中添加了很多显示中间变量的语句,到最后 release 时,当然要去掉这些语句。最差的方法当然是删掉这些代码,但是如果以后我们还想 debug 时,又得手动写,而且时间长了,我们自己都记不清该加哪些语句了。稍微好点的方法是把它们注释起来,但是同样,时间长了,哪些该注释,那些不该注释又混淆了。最好的方法就是用条件编译。我们可以定义一个宏 DEBUG
`define DEBUG
// conditional compilation
`ifdef DEBUG
// debug
`else
// release
`endif
这样,我们只需要选择是否注释第一行的宏定义就可快速在 debug 和 release 之间切换。
再比如在 Verilog 的模块中,针对不同的应用环境,我们要实现不同的模块,这时候也可以使用条件编译选择具体综合哪段代码。
相关阅读
reg:寄存器类型,只能在always和initial语句中被赋值,缺省值为x,若语句描述的是时序逻辑,寄存器变量对应寄存器;若语句描述的是组合逻辑,
本文大部分内容来自Clifford E. Cummings的《Simulation and Synthesis Techniques for AsynchronousFIFO Design》,经过自己的一
使用工具:Xilinx ISE 14.7主要操作就是将前一位的在加法器运算所得的标准位赋予的到下一位的运算过程中,一步一步推进即可:有两种实
简易数字频率计 原理:数字频率计的原理十分简单,简单的就是一句话和一幅图而已。 一句话:测量被测信号的频率,要清楚频率的定义,一言