设计规范很重要,特别是对于大的设计(无论软件还是硬件),不按规范走几乎是不可实现的。逻辑设计也是这样:如果不按规范做的话。过了一个月后调试时发现有错,回头再看自己写的代码,估计很多信号功能都忘记了,更不要说检错了;如果一个项目做了一半一个人走了,接班的估计得从头开始设计;如果需要在原来的版本基础上增加新功能,很可能也得从头来过,很难做到设计的可重用性。
逻辑设计方面的规范:
1、设计必须文档化。要将设计思路,详细实现等写入文档,然后经过严格评审通过,后才能进行下一步的工作。这样做乍看起来很花时间,但是从整个项目过程来看绝对要比一上来就写代码要节约时间,且这种做法可以使项目处于可控、可实现状态。
注:这一步对设计者的设计水平要求很高,可以看情况一步一步实现。
2、代码设计规范:
1) 设计参数化。比如要设计一个8位的计数器,写样去写:
`define DATA_WIDTH 4’h8
module counter(clock,
aclr,
sclr,
q
);
input clock;
input aclr;
input sclr;
output [DATA_WIDTH – 1 : 0] q;
//port signal description
wire clock;
wire aclr;
wire sclr;
wire [DATA_WIDTH – 1 : 0] q;
//internal signal description
reg [DATA_WIDTH - 1 : 0] q0;
assign q = q0;
always @(posedge clock or posedge aclr)
if(aclr)
q0 <= 8’h0;
else if(sclr)
q0 <= 8’h0;
else
q0 <= q0 + 1’h1;
endmodule
2) 端口信号排列要统一,一个信号只占一行,最好按从哪个模块来到哪个模块去的关系排列。如:
module module_name(
//globle signal
clk,
rst_n,
//sram bus signal
wr_n,
rd_n,
saddr,
sdin,
sdout,
//other signal
data_out,
……
);
3)信号的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。
说明:
i. 较短的单词可不作缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写。
示例:如下单词的缩写能够被大家基本认可。
clock 可缩写为 clk;
counter 可缩写为 cnt;
reset 可缩写为 rst;
temp 可缩写为 tmp;
initial 可缩写为 ini;
flag 可缩写为 flg;
statistic 可缩写为 stat;
increment 可缩写为 inc;
message 可缩写为 msg;
asynchronous clear 可缩写为 aclr
……
ii. 对于一个复位、使能、片选等类似的信号,若是低电平有效,其后面要加 _n,如,若是高电平有效,其后面可以不加(推荐),也可以加 _p:
rst_n , cs_n , oe_n ,aclr(or aclr_p);
iii. 命名中若使用特殊约定或缩写,则要有注释说明。
说明:应该在源文件的开始之处,对文件中所使用的缩写或约定,特别是特殊的缩写,进行必要的注释说明。
iv. 自己特有的命名风格,要自始至终保持一致,不可来回变化。说明:个人的命名风格,在符合所在项目组或产品组的命名规则的前提下,才可使用。(即命名规则中没有规定到的地方才可有个人命名风格)
v. 命名规范必须与所使用的系统风格保持一致,并在同一项目中统一,比如采用全小写加下划线的风格或大小写混排的方式,不要使用大小写与下划线混排的方式,用作特殊标识如标识高低电平的 _n , _p, 大小写混排的方式是允许的。
示例: Add_User不允许,add_user、AddUser、Reset_n 允许。
4) 一个模块尽量只用一个时钟,这里的一个模块是指一个module 或者是一个entity。,
在多时钟域的设计中涉及到跨时钟的设计最好有专门一个模块做时钟的隔离。这样做
可以让综合器综合出更优的结果。
5) 尽量在底层模块上做逻辑,在高层尽量做例化,顶层模块只到做例化,禁止出现任何胶连逻辑(glue logic),哪怕仅仅对某个信号取反。理由同上。
6) 在FPGA的设计上禁止用纯组合逻辑产生latch。如:
不要这样:
……
always @(en or data)
if (en)
outp = data;
……
应该这样:
……
always @(en or data)
if (en)
outp = data;
else
outp = ‘h0; //default value
……
7)一般来说,进入FPGA的信号必须先同步,所有模块的输出都要寄存器化,以提高工作频率,这对设计做到时序收敛也是极有好处的。
8)除非是低功耗设计,不然不要用门控时钟:这会增加设计的不稳定性,在要用到门控时钟的地方,也要将门控时钟用时钟的下降沿打一拍再输出与时钟相与。
9)尽量不要用计数器分频后的信号做其它模块的时钟,而要用改成时钟使能的方式,否则这钟时钟满天飞的方式对设计的可靠性极为不利,也大大增加了静态时序分析的复杂性。
如:
不要这样:
……
always @(posedge clock or posedge aclr)
if (aclr)
cnt0 <= 4’h0;
else
cnt0 <= cnt0 + 1’h1;
always @(negedge cnt0[3] or posedge aclr)
if(aclr)
cnt1 <= 8’h0;
else
cnt1 <= cnt1 + 1’h1;
……
应该这样:
……
always @(posedge clock or posedge aclr)
if (aclr)
cnt0 <= 4’h0;
else
cnt0 <= cnt0 + 1’h1;
always @(posedge clock or posedge aclr)
if(aclr)
cnt1 <= 4’h0
else if(cnt0 == 4’hf)
cnt1 <= cnt1 + 1’h1;
……
10) 11)状态机要写成3段式的(这是最标准的写法),即
……
//build the state flops
always @(posedge clk or negedge rst_n)
……
current_state <= next_state;
……
//state machine
always @ (current_state or ...)
……
case(current_state)
……
S1:
if ...
next_state = S2;
……
……
//outputs logic block
always @(current_state or …)
//default value
a = 1’b0;
b = 1’b0;
c = 1’b0;
……
case(current_state)
S1:
a = 1'b0;
S2:
b = 1'b1;
S3:
c = 1'b1;
default:
……
endcase
……
11)内部模块不能出现inout端口,如果需要,把inout端口拆分为一组input 和output;
12) 数据都十六进制或者二进制表示,且要标上位数。这样做综合器综合出的结果较好。
13)对齐一律用空格键,避免用TAB键。这样可以保证程序在其它机子上显示的格式一致,便于阅读。
文章评论(0条评论)
登录后参与讨论