FPGA设计原则以及代码规范.ppt
《FPGA设计原则以及代码规范.ppt》由会员分享,可在线阅读,更多相关《FPGA设计原则以及代码规范.ppt(35页珍藏版)》请在冰豆网上搜索。
FPGA设计原则以及代码规范,2009.4.22,FPGA设计原则,面积和速度的平衡与互换硬件原则系统原则同步设计原则,“面积”指一个设计消耗FPGA的逻辑资源的数量,一般可以用所消耗的触发器(FF)和查找表(LUT)来衡量,更一般的衡量方式可以用设计所占用的等价逻辑门数。
“速度”指设计在芯片上稳定运行,所能够达到的最高频率,这个频率由设计的时序状况决定,它和设计满足的时钟周期,PADtoPADTime,ClockSetupTime,ClockHoldTime,Clocktooutputdelay等众多时序特征量密切相关。
面积与速度,进一步了解FPGA内部的“面积”资源!
面积与速度的平衡与互换原则,速度换面积:
面积换速度:
FPGA设计和软件设计存在本质区别,要做到对所需实现的硬件电路“心有成竹”,对该部分硬件的结构与连接十分清晰,然后再用适当的HDL语句表达出来。
要明确FPGA的逻辑设计所采用的硬件描述语言(HDL)和软件语言(如C,C+等)的区别,HDL的本质作用在于描述硬件!
它的最终实现结果是芯片内部的实际电路。
硬件原则,硬件原则的另外一个重要理解是“并行”和“串行”的概念。
一般来说硬件系统比软件系统速度快,实时性高,其中一个重要原因就是硬件系统中各个单元的运算是独立的,信号流是并行的。
而C语言编译后,其机器指令在CPU的高速缓冲队列中基本是顺序执行的。
硬件原则并行处理,系统原则,一方面是一个硬件系统,例如一块板卡如何进行功能模块划分与任务分配,什么样的算法和功能适合放在传统FPGA里面实现,什么样的算法和功能适合放在DSP、CPU里面实现,或者在使用内嵌CPU和DSPBlock的FPGA中如何划分软硬件功能,以及FPGA的规模估算数据接口设计、开发成本的估算等。
另一方面就是具体到FPGA内部设计要有一个宏观上的合理安排,比如时钟域、模块复用、约束、面积、速度等问题。
同步设计原则同步与异步,在设计电路时,可以有异步电路和同步电路两种实现方法。
异步电路使用组合逻辑电路实现,没有统一的时钟信号,容易产生毛刺和竞争冒险。
同步时序电路使用组合逻辑和触发器实现电路功能,主要信号和输出信号都由时钟驱动触发器产生,能够避免毛刺,信号稳定。
同步设计时钟信号的质量和稳定性决定了同步时序电路的性能。
FPGA的内部有专用的时钟资源,如全局时钟布线资源、专用的时钟管理模块DUL、PLL等。
同步设计原则时钟,同步设计中,稳定可靠的数据采样必须遵从以下两条基本原则:
1、在有效时钟沿到达前,数据输入至少已经稳定了采样寄存器Setup时间之久。
这条原则简称满足Setup时间原则。
2、在有效时钟沿到达后,数据输入至少还将稳定保持采样寄存器Hold时间之久。
这条原则简称满足Hold时间原则。
同步设计原则建立/保持时间,FPGA设计代码规范,Verilog代码编写风格的必要性结构层次化编码时钟和RESET信号设计指南可综合性编码,Verilog代码编写风格的必要性,Verilog代码编写规范,经常是一个不太受欢迎的话题,但却是非常有必要的。
遵循代码编写规范书写的代码,很容易阅读、理解、维护、修改、跟踪调试、整理文档。
相反代码编写风格随意的代码,通常会很凌乱,会给开发者本人的调试、修改工作带来困难,也会给合作者带来很大麻烦。
编写规范的宗旨,缩小篇幅;提高整洁度;便于跟踪、分析、调试;增强可读性,帮助阅读者理解;便于整理文档;便于交流合作。
结构层次化编码框架图,1)结构的层次不宜太深,一般为3到5层即可;2)顶层模块最好仅仅包含对所有模块的调用,而不应该完成比较复杂的逻辑功能。
比较为合理的顶层模块由输入输出管脚声明、模块的调用与实例化、全局时钟资源、全局置位/复位、三态门控制等构成;3)所有的I/O信号,如输入、输出、双向信号等的描述在顶层模块完成;,结构层次化编码注意事项,)一般来说,进入FPGA的信号必须先同步,以提高系统工作频率;)所有模块的输出都要寄存器化,以提高工作频率,这对设计做到时序收敛也是极有好处的;)将相关的组合逻辑放在同一模块;,结构层次化编码注意事项,7)所有未使用的模块输入必须加上确定的逻辑值,不允许输入信号出现悬空状态;8)尽量少用组合逻辑设计;9)多用case语句少用if-else语句,if-else的嵌套不能超过四级;10)描述always块尽量简洁。
结构层次化编码注意事项,1)信号名一律小写,参数用大写。
2)对于低电平有效的信号结尾要用_n标记,如rst_n。
3)端口信号排列要统一,一个信号只占一行,最好按输入输出及从哪个模块来到哪个模块去的关系排列,这样在后期仿真验证找错时后方便很多。
如:
信号命名要规范化。
modulea(clk,rst_n,wren,rden,avalon_din,sdi,data_ready,avalon_dout);,尽量少用立即数,多用常量。
使用常量有以下优点:
(1)常量对于一个设计具有更多的灵活性;
(2)常量值只需要在一个地方修改。
方法:
对于Verilog程序,把常数和参数定义在一个或多个小文件中,例如文件design_parameters.v,然后在需要调用这些参数的模块中插入“includedesign_parameters.v“语句即可。
常量/参数化设计,时钟和RESET信号设计指南,避免在模块内部产生RESET信号:
(1)如果可能,尽量避免在模块内部产生RESET信号,或者避免用其它条件逻辑产生RESET信号;
(2)如果确实需要条件RESET信号,那么可以创建一个独立的RESET信号,再创建一个独立的条件RESET产生逻辑模块。
DFF1:
always(posedgeclk_125m)beginif(!
rst_n)q=1b0;elseq=d;end,DFF2:
always(negedgeclk_125m)beginif(!
rst_n)q=1b0;elseq=d;end,例如,避免使用混合时钟沿,
(1)在你的设计中,要避免同时使用上升沿触发和下降沿触发这两种触发方式的寄存器。
(2)如果在你的设计中必须同时使用大量的上升沿和下降沿出发的触发器,那么应该把他们放在不同的模块中。
在多时钟域的设计中涉及到跨时钟域的设计中最好有专门一个模块做时钟域的隔离。
这样做可以让综合器综合出更优的结果。
这里的一个模块是指一个module。
一个模块尽量只用一个时钟,避免在模块内部产生时钟,避免使用内部产生时钟的方法,例如采用计数器分频出来的脉冲直接拿去当作时钟使用,是不允许的,这种时钟对设计的可靠性极为不利.,逻辑分频时钟:
always(posedgeclk_125m)beginif(!
rst_n)clk_div_62m5=1b0;elseclk_div_62m5=!
clk_div_62m5;endalways(posedgeclk_div_62m5)beginif(!
rst_n)data_out=8h00;elsedata_out=data_in;end,时钟使能方式:
always(posedgeclk_125m)beginif(!
rst_n)en_clk_62m5=1b0;elseen_clk_62m5=!
en_clk_62m5;endalways(posedgeclk_125m)beginif(!
rst_n)data_out=8h00;elseif(en_clk_62m5)data_out=data_in;end,避免在RTL代码中直接使用门控时钟,门控时钟会增加设计的不稳定性,always(en1oren2)beginif(!
rst_n)data_out=8h00;elsedata_out=data_in;end,避免使用门控时钟,D,Q,en1,en2,data_in,data_out,Verilog中,用always块设计组合逻辑电路时,1)在赋值表达式右端参与赋值的所有信号都必须在always(敏感电平列表)中列出,2)always中if语句的判断表达式必须在敏感电平列表中列出。
3)确保过程模块敏感信号列表中的信号是必需的。
敏感信号列表中没必要出现的信号会降低仿真速度。
敏感变量的描述完备性,错误写法:
always(aorborc)begine=dend,敏感变量的描述完备性,
(1)在Verilog语言中的case语句对应一个单级的多选电路,if-elseif-else语句对应于一个优先编码的多级组合选择电路。
(2)如果你的设计中没有优先级的要求,最好使用case语句,不要使用if-elseif-else语句进行描述。
Case语句和If-Else语句,不推荐这种写法:
具有优先级例子1:
没有优先级例子1:
优先级电路,不推荐这种写法,同时不推荐大小写混合使用,具有优先级例子2:
优先级电路,例:
位置映射法Blockblock_1(signal_a,signal_b);例:
信号名映射法blockblock_1(.signal_a(signal_a),.signal_b(signal_b);,在Verilog中,有两种模块调用的方法,一种是位置映射:
模块名(连接端口1信号名,连接端口2信号名,连接端口3信号名,);另一种为信号名映射法:
模块名(.端口1信号名(连接端口1信号名),.端口2信号名(连接端口2信号名),.端口3信号名(连接端口3信号名),);,模块调用规范,在书写Verilog可综合代码时,在always(posedgeclk)模块中,总是使用非阻塞赋值方式,否则会产生RTL级仿真和门级仿真功能不一样的现象。
同一个always中不能混用阻塞,非阻塞赋值。
阻塞和非阻塞赋值(Verilog),Error:
状态机要写成3段式的(这是最标准的写法),即always(posedgeclkornegedgerst_n)(第一段).current_state=next_state;.always(current_state.)(第二段).case(current_state).s1:
if.next_state=s2;.always(posedgeclkornegedgerst_n)(第三段).elsecase(current_state)s1:
a=1b0;s2:
b=1b1;default:
.,状态机的写法,小结,以上列出的代码编写规范无法覆盖代码编写的方方面面,还有很多细节问题,需要在实际编写过程中加以考虑。
并且有些规定也不是绝对的,需要灵活处理,并不是律条。
但是在一个项目组内部、一个项目的进程中,应该有一套完成、统一的代码编写规范来作为约束,才能做到整洁、可读性好的代码,提高项目研发进度。
THEEND,谢谢大家!