Verilog代码可移植性设计
1.
localparam,实例代码如下:
module tm1(
input clk;
input rst_n;
output[M:0] pout;
localparam N = 4;
localparam M = N-1;
reg[M:0] cnt;
always @(posedge clk or negedge rst_n)
assign pout = cnt;
endmodule
parameter,实例代码如下:
module tm1
input clk;
input rst_n;
output[M:0] pout;
localparam M = N-1;
reg[M:0] cnt;
always @(posedge clk or negedge rst_n)
assign pout = cnt;
endmodule
module lvdsprj(
input clk;
input rst_n;
output[M:0] pout;
localparam N = 5;
localparam M = N-1;
tm1
endmodule
2.
从定义方式上看,verilog语法中的宏定义和C还是略有区别,如verilog中的宏定义如下:
`define
3.
`ifdef、`else 和`endif,这些编译指令用于条件编译,如下所示:
`ifdef windows
parameter
`else
parameter
`endif
在编译过程中,如果已定义了名字为windows的文本宏,就选择第一种参数声明,否则选择第二种参数说明。` else程序指令对于`ifdef 指令是可选的。
条件编译其实是很有用的,尤其在代码移植过程中。在工程中,如果我们编写某段代码逻辑(可能不止一段),而在实际应用中并不需要(或者只是作为调试使用,或者可能在别的工程中使用),通常的做法可能是将该部分逻辑进行注释。而当再次希望使用这部分代码的时候,一个常见的问题出现了,取消注释的时候往往可能不记得哪些逻辑是和这个功能块相关并被注释了。因此,这个时候条件编译就派上用场,可以省去我们很多的郁闷时间。特权同学过去对这个命令很不感冒,通常只是感觉很多有用的没用的代码在那里显得很紊乱,殊不知其实某些情况下它还是很“给力”的。
① 工程中一些通用常量的定义多用parameter或`define,便于更改。
② 部分暂时不需要的功能块用`ifdef来“注释”。
③ 模块的进出信号接口尽量标准化(可以是比较“官方”的标准化,当然也可以是自定义的“草根”标准化),利于将来的复用。
④ 注释要清晰明了,不说废话,即便在一个代码源文件里,也尽量将各个不同的功能块代码“隔离”。
⑤ 配套文档和说明必不可少。
⑥ 信号命名尽量“中性”化。比如某模块的时钟输入是25MHz,那么可以取个中性的信号名clk,而不需要取clk_25m,但必须在注释中标明频率。这样做的好处是将来移植到时钟输入为50MHz或是其他频率的应用中,不必再费劲的改clk_25m为clk_50m了。
总结:
define:
可以跨模块的定义;
parameter:
本module内有效的定义,可用于参数传递;
localparam:
关于localparam,这个关键字书上很少会讲到。但是大公司的代码里经常会看到
本module内有效的定义,不可用于参数传递;localparam cannot be used within the module port parameter list.
一般情况下,状态机的参数都是用localparam的。
用来生成循环,生成维数可扩展的模块,localparam是局部参数,但它不能被重定义,也就是说在实例化的时候不能通过层次引用进行重定义,例如parameter可以通过#(参数)来进行重新定义,但是localparam不可以,只能通过源代码来改变。