verilog代码中的"parameter" "#" "localparam"

Verilog代码可移植性设计

1.       参数定义

localparam,实例代码如下:

module tm1(

            clk,rst_n,

            pout

        );

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)

    if(!rst_n) cnt <= 0;

    else cnt <= cnt+1'b1;

   

assign pout = cnt;

 

endmodule

         其实所谓localparam即local parameter(本地参数定义)。简单的说,通常我们习惯用parameter在任何一个源代码文件中进行参数定义,如果不在例化当前代码模块的上层代码中更改这个参数值,那么这个parameter可以用localparam代替。而localparam定义的参数是可以如parameter在上层文件中被更改的。具体的区别待parameter的用法实例后大家就能明白。

parameter,实例代码如下:

module tm1

        #(parameter N = 4)

        (

            clk,rst_n,

            pout

        );

input clk;      //外部输入25MHz时钟

input rst_n;    //外部输入复位信号,低电平有效

 

output[M:0] pout;  

 

localparam M = N-1;

 

reg[M:0] cnt;      

 

always @(posedge clk or negedge rst_n)

    if(!rst_n) cnt <= 0;

    else cnt <= cnt+1'b1;

   

assign pout = cnt;

 

endmodule

         tm1.v的上层模块中,可以用lvdsprj.v模块中的方式对其已经定义的parameter参数进行重新定义,而相应的localparam定义是不可以在lvdsprj.v模块中进行重新设定的。Lvdsprj.v模块的代码如下:

module lvdsprj(

            clk,rst_n,

            pout

        );

input clk;

input rst_n;

 

output[M:0] pout;  

 

localparam N = 5;

localparam M = N-1;

 

tm1     #(.N(5))

        uut1(

            .clk(clk),

            .rst_n(rst_n),

            .pout(pout)

        );

 

endmodule

         在verilog设计中,我们习惯将状态机的状态量用parameter来申明定义,它的适用范围通常是某个代码模块,或者其相关的上一层模块可对其进行重新申明定义。而如果工程中有多个模块里要用到同样的

 

2.       宏定义

从定义方式上看,verilog语法中的宏定义和C还是略有区别,如verilog中的宏定义如下:

`define         5

         在使用该宏定义值时,通常M应该表示为`M。之所以不是很提倡滥用宏定义,是因为它不像parameter那么“中规中矩”的作用有某几个特定的源代码文件中。一旦`define被编译,其在整个编译过程中都有效,只有当遇到`undef命令才能使之失效。也即它通常会影响工程的其他模块,尤其当多个同样宏名定义时,如果不注意有可能照成定义的混乱。

 

3.       条件编译

`ifdef、`else 和`endif,这些编译指令用于条件编译,如下所示:

`ifdef windows

parameter  SIZE = 16

`else

parameter  SIZE = 32

`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不可以,只能通过源代码来改变。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: veriloglocalparam是一种局部参数,用于在模块内部定义常量。它与parameter的区别在于,localparam只能在模块内部使用,而parameter可以在模块内外使用。localparam的值在编译时确定,不能在运行时改变。localparam的语法如下: localparam [size] name = value; 其,size是可选的,表示参数的位宽;name是参数的名称;value是参数的值。localparam的作用是方便代码的编写和维护,可以避免在代码使用魔法数字,提高代码的可读性和可维护性。 ### 回答2: Veriloglocalparam指令可以定义一个局部参数,其作用类似于parameter,但不同的是,localparam的值只在当前block有效。 localparam定义格式为:localparam [bitwidth] name = value; 其,[bitwidth]是可选的,如果不指定,则根据赋值表达式自动确定参数位宽;name为参数名;value为参数值。 localparam的用法主要有以下两个方面: 1. 定义常量 localparam可以定义一个常量,以便在代码引用,提高代码的可读性和可维护性。例如: localparam WIDTH = 8; 2. 确定内部参数位宽 localparam还可以配合其他指令使用,例如,可以使用localparam定义一个参数位宽,在下面使用参数位宽定义wire或reg变量的宽度。例如: localparam ADDR_WIDTH = 8; module my_module (input clk, input [ADDR_WIDTH-1:0] addr, input [7:0] data_in, output [7:0] data_out); wire [ADDR_WIDTH-1:0] idx; reg [7:0] mem [0:2**ADDR_WIDTH-1]; assign idx = addr; always @(posedge clk) begin mem[idx] <= data_in; data_out <= mem[idx]; end endmodule 在上面的例子localparam ADDR_WIDTH定义了地址位宽为8,然后在module定义用到了addr变量和idx变量的定义。在reg类型的数组定义了2**ADDR_WIDTH个元素。这样可以灵活地在代码调整位宽而不影响其他部分的代码。 总之,localparam是一种非常方便的定义局部变量的方法,可以提高代码的可读性和可维护性,也可以使代码更灵活。 ### 回答3: verilog是一种硬件描述语言,用于设计数字电路。localparam是一种verilog语言的关键字,用于指定一个局部常量。它在代码模块或分层模块定义局部常量,该常量在模块定义,对该模块范围内的其他变量可见。 在verilog代码,在模块内,我们经常需要定义各种常量。有时候这些常量是公用的,有时候我们只需要在模块内使用,这时候localparam就能够发挥作用。与parameter不同,localparam是局部变量,只在当前模块内有效。localparam通常被用来表示比较稳定的值,比如时钟周期、时序等重要参数。 使用localparam的语法比较简单,它仅仅需要在模块定义一个常量,并对它进行赋值操作,如下所示: ``` module test (); localparam WIDTH = 16; // code here endmodule ``` 在这个例子,我们定义了一个名为WIDTH的局部常量,该常量被赋值为16。这个常量可以在当前模块任何地方使用。我们也可以根据需要定义多个localparam常量。 使用localparam有以下几个核心的好处: 1. 局部常量可以提高代码的可读性和可维护性。使用localparam,我们可以将常量与相关的逻辑分组在一起,从而更容易地阅读和修改代码。 2. 常量的值不能被修改,因此可确保代码在使用时,常量的值保持不变,不会被轻易改变。 3. 可减少软件代码错位的可能性。定义大量的常量,可以减少因为手写数字而引起的代码错位问题,使得代码更容易阅读和维护。 总体来说,localparamverilog语言一个非常有用的功能,可以使得硬件设计更加容易,并且可读性和可维护性更强,对于硬件系统的开发,有非常重要的作用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值