1、编写注意事项
(1)大小写敏感;
(2)编译指令中的前导符号;
2、代码风格
整齐、统一、易懂、精简
(1)命名规则
reg[3:0] second_counter;
reg[3:0] minute_counter;
reg[3:0] secondeCounter;
reg[3:0] minuteCounter;
reg flagDelayforZeroCycle;
reg flagDelayforOneCycle;
reg flagDelay0;
reg flagDelay1;
电平敏感命名:一般来说是高电平有效,若是低电平有效,通过一些前缀或者后缀方法加以区别。
output CS_n,nCS,_CS;//低电平有效
方向敏感命名:
input clk_in;
output outClk;
若子模块A的输出端口连接到子模块B的输入端口:
wire data;
xxxm0(.dataIn(data),...);
yyym1(.dataOut(data),...);
(2)端口声明、参数声明、映射方式要一致
(3)空格空行
(4)注释编写
3、顶层模块设计
3.1、概念
顶层模块概念:直接提交给编译器进行处理并在FPGA芯片上直接实现的模块或实体与main函数类似,但对于FPGA设计来说,任一模块或者实体都可以被设置为顶层模块。
特点:
(1)顶层模块代码一般采用结构化的描述方法,只存在例化语句;
(2)只有顶层模块的端口才被分配到具体的FPGA芯片物理管脚上去,顶层模块众多子模块的端口仅仅对应FPGA芯片内部的一些连线资源;
(3)只有顶层模块才能配备约束文件、综合约束文件、时序约束文件。若子模块也需要相应的约束,只能在顶层模块的约束文件中写入一些代码,并加上相应的正确层级指示。
3.2、分类
(1)按功能分:控制类、通信链路类、数据处理类
(2)面向分类:接口处理类和内部逻辑类
编写纯净的组合或者时序逻辑:将对应组合逻辑代码和纯时序逻辑的代码分离开来
组合逻辑电路:数字电路满足任意时刻的输出仅仅取决于该时刻的输入。
always@(sel, b)
begin
if(sel = 1'b1)
a = b;
end
分析:
输入sel , b;输出a
当sel为1时,a完全取决于b;
当sel为0时,a保持最近一次sel为1时b的值,与当前值无关。
此时会引入锁存器,具有存储功能的单元,实际实现的是一个时序逻辑电路。
锁存器缺点:
第一:毛刺敏感,造成信号不稳定;
第二:FPGA中一般没有锁存器,需要一个触发器+逻辑门;
第三:锁存器的引入会对时序分析造成困难;
所以:务必确认代码覆盖了组合逻辑的所有分支,以避免锁存器的引入。
always@(sel, b)
begin
if(sel = 1'b1)
a = b;
else
a = 1'b0;
end
严格按照电信号的传递顺序来安排串行组合逻辑的语句顺序。
always@(a,b,c,d)
begin
m0 = a&b;
m1 = c&d;
dOut = m0&m1;
end
尽管颠倒always中语句顺序,综合出来的电路结果一致,但会对仿真产生许多不利影响。
时序逻辑电路:
always@(posedge clk)
begin
reg0 <= dIn;
reg1 <= reg0;
dOut <= reg1;
end
注意:
第一:要么上升沿触发,要么下降沿触发
第二:注意语句顺序,纯时序语句顺序的颠倒对设计功能及仿真不会有影响,因为时序赋值本身就是并行的。
清晰的时序逻辑描述方法
例如:计数器
always@(posedge clk)
begin
if(rst)
begin
count <= 1'b0;
end
else
begin
count <= nextCount;
end
end
assign nextCount = count + 1'b1;
always@(posedge clk)
begin
if(rst)
begin
count <= 1'b0;
end
else
begin
count <= count + 1'b1;
end
end