编写可综合的FPGA代码
在接触Verilog 语法参考手册的时候,我们发现其提供了一组非常丰富的功能来描述硬件。所以大家往往会疑惑那些Verilog语句是可综合的,那些是只能用于写Testbench的,其实,参考手册中只有一小部分语句是可综合的,但是这一小部分可综合的语法确是我们应用最为频繁的,可综合的意思就是可以通过物理工具进行编译、综合、布局布线,最终在FPGA上实现。
参考下面的例子。
reg [7:0] memory[1:2**22];
Initial begin
memory[1]=8’h1;
memory[2]=8’h2;
end
该示例虽然可以正常的仿真,但是用FPGA工具编译综合,最终在FPGA上实现。代码中定义了一个4M Byte的存储器,其实在FPGA中时没有这样的物理资源可以与其对应的,另外,FPGA编译综合工具在编译的时候也将忽略IniTIal块语句。
本文重点介绍如何设计可综合的Verilog代码。在设计可综合的Verilog代码的时候,我们应该遵循怎样的原则。
1. 坚持FPGA的同步设计原则
包括以下几个方面:
使用同步复位电路。
避免使用锁存器; 尽可能使用同步寄存器。
避免使用门控,派生或分频时钟。
使用时钟使能,而不是多个时钟。
实现所有异步信号的正确同步。
2. 理解综合工具的能力和局限性
充分了解综合工具的能力和局限性将有助于提高FPGA设计的性能、逻辑性、以及资源利用率和可生产性。熟悉特定FPGA系列的内部构造,以及综合工具所忽略或不支持的语言以及建议的寄存器,状态机,三态和其他推荐的编码风格非常重要。
3. 忽略语言结构
FPGA综合工具会忽略延迟值和时间标度编译器指令。设计人员经常利用延迟来使分析仿真波形变得更容易,如下例所示。
`define DLY 1
always @(posedge clk) begin
Data_out
end
因为潜在的综合和仿真失配,所以不鼓励使用这样的结构。例如,如果上例中的“DLY超过时钟周期,则综合电路可能在功能上不正确,因为它不会匹配仿真结果。绝大多数FPGA综合工具都忽略编译器指令,例如celldefine和endcelldefine。
FPGA综合工具忽略iniTIal块描述。
综合工具为Verilog门级原语(如nmos,pmos,cmos,pullup,pulldown,
tranif0,tranif1,tran等)提供各种级别的支持。例如,XST不支持Verilog tranif原语,而Synplify则支持。 尽管Xilinx FPGA体系结构不具有门级原语的直接等价物,但一些综合工具将其转换为功能等效的门级开关。 以下是nmos转换的一个例子。
module nmos_switch(output out,intput data,control);
Assign out =control?Data :1’bz ;
endmoudle
4. 不支持的语句结构
不支持的语句结构包括有:用户自定义的原语(UDP),repeat,wait,
fork/join,deassign ,event,force/release 语句。也不支持模块内寄存器和网络的分层引用,如:
module mymodule1;
assign my_net =top.my_mudule2.my_net ;
endmoudle
相等和不相等运算符(===和!==)的支持级别取决于综合工具。有些综合工具在遇到一个等式和不等式运算符时会产生一个错误,而另一些则会将运算符转换为逻辑等式(==和!=)。
5. 2种状态和4种状态的比较
4态值(‘0’,‘1’,‘x’,‘z’)本质上是不可综合的。 FPGA架构仅支持2态值(逻辑“0”和“1”),综合工具将应用不同的规则来优化“z”和“x”综合的过程。这将导致综合和仿真结果之间的不匹配和其他错误。 在实现三态IO缓冲区的时候只使用‘z’值。
6. translate_on/translate_off
translate_off和translate_on表示让综合工具忽略Verilog代码的一部分。这些指令通常用于忽略IP核模型中的行为代码部分。以下是使用这些指令的示例。
module bram_2k_9 ( input clka, input [0 : 0] wea,
input [10 : 0] addra,
output [8 : 0] douta,
input [8 : 0] dina);
// synthesis translate_off
// behavioral descripTIon of bram_2k_9
// synthesis translate_on
endmodule // bram_2k_9
7. 特殊的编译指令也无法被综合
syn_keep指令可防止综合工具删除指定的信号。它适用于网络和组合逻辑。 该指令通常用于禁用不需要的优化,并保留手动创建的复制。综合工具不同syn_keep的作用可能会不同。例如,XST不会将约束传播到综合网表,这并不妨碍物理实现工具的优化。syn_preserve防止寄存器优化。XST还支持“Equivalent Register Removal”选项,相当于syn_preserve。syn_noprune确保如果未使用实例化原型的输出,则原型未被优化。XST也支持“OpTImize Instantiated Primittives”选项,相当于syn_noprune。
8. parallel_case和full_case
如果在case,casex或casez语句中指定了full_case指令,则会阻止综合工具创建其他逻辑以涵盖未描述的条件。使用full_case指令可能会有更紧凑的效果。parallel_case指令强制将case语句综合成为并行复用器而不是优先级编码结构。使用parallel_case指令可能会提高电路的时序性能。
full_case和parallel_case指令的确切作用取决于综合工具。而且,使用这些指令也会导致综合和仿真不匹配。出于这些原因,不建议在FPGA设计中使用full_case和parallel_case指令。相反,设计师可以通过一个case语句的实现来达到同样的效果。例如,删除重叠的大小写条件会导致不必要的parallel_case指令。
9. 编译器指令 `default_nettype
Verilog-2001标准定义了一个`default_nettype编译器指令。 如果该指令被分配为“无”,则必须声明所有的1bit 信号网络。
// no `default_nettype
wire sum; // declaration is not required
assign sum = a + b;
`default_nettype none
wire sum; // must be declared
assign sum = a + b;