Verilog HDL语言设计框架及代码风格!
模块(module)
module是Verilog代码编写的主体。那么,这个主体有什么内容就值得一个新手关注。一个模块(module)中有很多内容。下面介绍一个完整的module参考模型(这个模型仅供参考)。
注:使用这个模块基本没有问题,放心使用!
完整module参考模型:
`define AAAA aaaa //宏定义
`include"abc.v" //文件包含
`timescale 1ns/1ns //时间刻度定义
//-----------------------------------
module main (完整端口列表); //模块声明,端口列表要完整
input [宽度] a; //输入、输出的位宽
output [宽度] b1;
output [宽度] b2;
inout [宽度] c;
//---------------------------------------
//wire [宽度] b1; //b1是线网型输出,可以省略
reg [宽度] b2; //b2是寄存器型输出,常用于时序电路
reg [宽度] e; //模块内使用的向量
wire [宽度] f; //模块内使用的连接线
integer [宽度] g; //整数型
//-----------------------------------
parameter H=数值; //参数声明
//------------------------------------
//时序逻辑电路设计,使用非阻塞赋值
always @ (posedge 信号 or negedeg 信号)
begin
b2<=a;
end
//-------------------------------------
//组合逻辑设计,使用阻塞赋值
always @ (信号)
begin
b1=a;
end
//-------------------------------------
//简单或者逻辑清晰的组合逻辑,这是数据流语句
assign = b1=~a;
//-------------------------------------
//门级调用
and and1 (b1,a,~a);
//------------------------------------
//模块实例化,可以提高模块的可读性
ZZZ my_zzz (端口连接);
endmodule
所有的module设计都是取自以上模板的某几个部分来完成,如果设计(验证)的代码编写都可以照搬这个模块;久而久之,可以编写出美观的代码(当然,只要自己编写的代码别人看着舒服就可以,语言具有灵活性。)
代码风格:
代码风格可不是说我想怎么写就怎么写,我感觉这个好看就可以了,我想自成一派(怎么不上天去)。风格,其实在某种程度上是大家的“习惯”,这种“习惯”是为了帮助设计者(新手,例如我)尽可能减少不必要的错误。比如,大家说西瓜和羊肉不能一起吃。那偏偏你不信,你去吃一次;还好就是拉肚子,自己难受。代码风格就是尽可能让你少拉肚子或者说不拉肚子。
常见的代码风格如下:
1、多重驱动问题
代码如下:
reg clk,rst;
reg [1:0] out,a,s;
always @ (posedge clk)
if (rst)
out=2'b00;
......
always @ (posedge clk)
if (a==0)
out=2'b11;
......
在这个代码中,如果不懂数字电路的人可能会这样想。每次到了时钟上升沿时,如果复位信号有效则输出为0;如果a==0则输出11。看似功能清晰,其实这里面出现多重驱动。在可综合电路中,一个信号的赋值只会发生在一个always中;如果如上述代码,这个电路会尝试给同一个输出赋值,这样会“碰撞”。
这种情况是我们没有把思路正确变为电路。设计思路不是“在这些情况下,输出都是什么”,而是“每个输出在这些情况下都应该输出什么”,我们要想象自己是一个电路(如果做芯片,就想象自己是一个芯片)。
2、敏感列表不完整
对于组合电路,在@引导的敏感列表必须包含完整的敏感列表。对于时序电路,@的敏感事件如果不全会变成异步电路,不过异步电路的设计很多综合器不支持(在公司,设计人员就是无用功)。
如果敏感列表不完整,会造成逻辑错误。甚至有可能出现锁存器。比如:
always @ (a) //敏感列表没有b
c=a~^b;
b的变化不会促使always结构变化,这样就是一个带控制的锁存器。
修改代码如下:
always @ (a or b)
c=a~^b;
3、if和else不成对出现
4、case语句缺少default
5、组合和时序混合设计(这个是废话)
注:
reg型输出不代表输出一定是reg 型。输出只能说大部分是reg 型。
以上都是一些前人经验,不要犯这种低级错误。当然,可以自己故意编写几个这种代码玩玩。不过,你会发现有的时候即使犯错也会得到你想要的结果,这是要感谢你的编译器和综合器。对不对看天意。
还有一些小习惯,用了有帮助,不用也无所谓。
1、电路中尽可能使用参数化设计;便于修改,顶层模块的参数影响子模块。
2、不要使用Tab,使用空格;转移代码的时候格式不会出错,功能没有任何问题,说白了还是一个颜控。
3、设计中只能使用单行注释,注释量要占到设计代码的35%以上;人会遗忘,便于记忆。端口列表必须写清注释。
4、在模块划分中。层次化设计的要求是子模块之间相互独立;时钟模块和复位模块单独划分;相关逻辑放在一起。
5、命名的一些规则,比如。input write_clk;
代表写时钟;模块实例化u_模块名_n
这里的模块名是实例化模块的名称(不容随意修改),n表示实例化的次数。
总结:
这篇博客内容属于值得反复去看的。如同品茶一般,慢慢回味里面的妙趣。
感想:
无