为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

VERILOG语言编写规范

2022-05-05 2页 doc 240KB 8阅读

用户头像 个人认证

is_800993

暂无简介

举报
VERILOG语言编写规范LELEwasfinallyrevisedonthemorningofDecember16,2020VERILOG语言编写规范VERILOG语言编写规范1目的本规范的目的是提高书写代码的可读性可修改性可重用性,优化代码综合和仿真结果,指导设计工程师使用VerilogHDL规范代码和优化电路,规范化公司的ASIC设计输入从而做到1.逻辑功能正确2.可快速仿真3.综合结果最优如果是hardwaremodel)4.可读性较好。2范围本规范涉及VerilogHDL编码风格,编码中应注意的问题,Testbench的编码等。本规范适用于V...
VERILOG语言编写规范
LELEwasfinallyrevisedonthemorningofDecember16,2020VERILOG语言编写VERILOG语言编写规范1目的本规范的目的是提高书写代码的可读性可修改性可重用性,优化代码综合和仿真结果,指导工程师使用VerilogHDL规范代码和优化电路,规范化公司的ASIC设计输入从而做到1.逻辑功能正确2.可快速仿真3.综合结果最优如果是hardwaremodel)4.可读性较好。2范围本规范涉及VerilogHDL编码风格,编码中应注意的问,Testbench的编码等。本规范适用于Verilogmodel的任何一级(RTLbehavioral,gate_level),也适用于出于仿真,综合或二者结合的目的而设计的模块。3定义VerilogHDL:Verilog硬件描述语言FSM:有限状态机伪路径:静态时序分析(STA)认为是时序失败,而设计者认为是正确的路径4引用和参考资料下列标准包含的条文通过在本标准中引用而构成本标准的条文在标准出版时所示版本均为有效所有标准都会被修订使用本标准的各方应探讨使用下列标准最新版本的可能性ActelHDLCodingStyleGuiderSunMicrosystemsRevisionVerilogStyleandCodingGuidelines5规范内容Verilog编码风格本章节中提到的Verilog编码规则和建议适应于Verilogmodel的任何一级(RTLbehavioral,gate_level)也适用于出于仿真,综合或二者结合的目的而设计的模块。命名规范选择有意义的信号和变量名,对设计是十分重要的。命名包含信号或变量诸如出处,有效状态等基本含义下面给出一些命名的规则。1.用有意义而有效的名字有效的命名有时并不是要求将功能描述出来如For(I=0;I<1024;I=I+1)Mem[I]<=#132’b0;For语句中的循环指针I就没必要用loop_index作为指针名。2.用连贯的缩写长的名字对书写和记忆会带来不便,甚至带来错误采用缩写时应注意同一信号在模块中的一致性。缩写的例子如下:AddraddressPntrpointerClkclockRstreset3.用名字前加小写n表示低电平有效高电平有效的信号不得以下划线表示短暂的引擎信号建议采用高有效如nRst,nTrdy,nIrdynIdsel.4.大小写原则名字一般首字符大写,其余小写(但parameter,integer定义的数值名可全部用大写),两个词之间要用下划线连接(或第二个单词首字母大写)如:Packet_addr,Data_in,Mem_wr,Mem_ce_Or:PacketAddr,DataIn,MemWr,MemCe5.全局信号名字中应包含信号来源的一些信息如:D_addr[7:2]这里的D指明了地址是解码模块(Decodermodule)中的地址.6.同一信号在不同层次应保持一致性7.自己定义的常数类型等用大写标识如:parameterCYCLE=100.8.避免使用保留字如inoutxz等不能够做为变量端口或模块名9.添加有意义的后缀使信号名更加明确常用的后缀如下芯片的双向信号-xbio芯片的三态输出_xz芯片的漏极开路输出_xod芯片原始输出信号_xo芯片原始输入信号_xi下降沿有效的寄存器_f连到三态输出的信号_z寄存前的信号_next时钟信号_ClkModules1.顶层模块应只是内部模块间的互连Verilog设计一般都是层次型的设计,也就是在设计中会出现一个或多个模块,模块间的调用在所难免。可把设计比喻成树,被调用的模块就是树叶,没被调用的模块就是树根,那么在这个树根模块中,除了内部的互连和模块的调用外,尽量避免再做逻辑,如:不能再出现对reg变量赋值等,这样做的目的是为了更有效的综合,因为在顶层模块中出现中间逻辑,Synopsys的designcompiler就不能把子模块中的逻辑综合到最优。2.每一个模块应在开始处注明文件名功能描述引用模块设计者设计时间及版权信息等如/*===========================*\Filename﹕Author﹕whqDescription﹕FiledescriptionCalledby﹕TopmoduleRevisionHistory﹕timeyy-mm-ddRevisionEmailCopyright(c)1999,~~~~~~~~~~~~~,Allrightreserved/*===========================*\3.不要对Input进行驱动,在module内不要存在没有驱动的信号,更不能在模块端口中出现没有驱动的输出信号,避免在仿真或综合时产生warning,干扰错误定位4.每行应限制在80个字符以内以保持代码的清晰美观和层次感一条语句占用一行如果较长,超出80个字符则要换行。5.电路中调用的module名用Uxx标示。向量大小表示要清晰,采用基于名字(name_based)的调用而非基于顺序的(order_based)。InstanceUInstance2(.DataOut(DOUT),.DataIn(DIN),.Cs_(Cs_));6.用一个时钟的上沿或下沿采样信号,不能一会儿用上沿,一会儿用下沿。如果既要用上沿又要用下沿,则应分成两个模块设计。建议在顶层模块中对Clock做一非门,在层次模块中如果要用时钟下沿就可以用非门产生的PosedgeClk_,这样的好处是在整个设计中采用同一种时钟沿触发,有利于综合。基于时钟的综合策略7.在模块中增加注释对信号,参量,引脚,模块,函数及进程等加以说明,便于阅读与维护。8.Module名要用大写标示,且应与文件名保持一致。如ModuleDFF_ASYNC_RST(Reset,Clk,Data,Qout);严格芯片级模块的划分只有顶层包括IO引脚(pads),中间层是时钟产生模块,JTAG,芯片的内核(CORE),这样便于对每个模块加以约束仿真,对时钟也可以仔细仿真。模块输出寄存器化对所有模块的输出加以寄存(如图1)使得输出的驱动强度和输入的延迟可以预测,从而使得模块的综合过程更简单-输出驱动的强度都等于平均的触发器驱动强度图19.将关键路径逻辑和非关键路径逻辑放在不同模块保证DC可以对关键路径模块实现速度优化,而对非关键路径模块实施面积优化在。同一模块DC无法实现不同的综合策略,将相关的组合逻辑放在同一模块,有助于DC对其进行优化因为DC通常不能越过模块的边界来优化逻辑。NetandRegister1.一个reg变量只能在一个always语句中赋值2.向量有效位顺序的定义一般是从大数到小数尽管定义有效位的顺序很自由,但如果采用毫无规则的定义势必会给作者和读代码的人带来困惑,如Data[-4:0],则LSB[0][-1][-2][-3][-4]MSB,或Data[0:4]则LSB[4][3][2][1][0]MSB这两种情况的定义都不太好,推荐Data[4:0]这种格式的定义。3.对net和register类型的输出要做声明在PORT中。如果一个信号名没做声明Verilog将假定它为一位宽的wire变量。4.线网的多种类型。寄存器的类型。Expressions1.用括号来表示执行的优先级尽管操作符本身有优先顺序,但用括号来表示优先级对读者更清晰,更有意义。If((alpha=delta))....比下面的表达更合意If(alpha=delta)...(判断逻辑应是化简过后的最简形式!)2.用一个函数(function)来代替表达式的多次重复如果代码中发现多次使用一个特殊的表达式,那么就用一个函数来代替,这样在以后的版本升级时更便利,这种概念在做行为级的代码设计时同样使用,经常使用的一组描述可以写到一个任务(task)中。IF语句1.向量比较时比较的向量要相等当比较向量时verilog将对位数小的向量做0扩展以使它们的长度相匹配它的自动扩展为隐式的建议采用显示扩展这个规律同样适用于向量同常量的比较RegAbc[7:0];RegBca[3:0];......If(Abc=={4’b0,Bca})begin.......If(Abc==8’b0)begin2.每一个If都应有一个else和它相对应在做硬件设计时,常要求条件为真时执行一种动作而条件为假时执行另一动作即使认为条件为假不可能发生,没有else可能会使综合出的逻辑和,RTL级的逻辑不同。如果条件为假时不进行任何操作,则用一条空语句。always@(Cond)beginif(Cond)DataOut<=DataIn;End3.应注意If..elseif...elseif...else的优先级4.如果变量在If-else或case语句中做非完全赋值则应给变量一个缺省值。即V1=2’b00;V2=2’b00;V3=2’b00;If(a==b)beginV1=2’b01;case语句通常综合成一级多路复用器(图的右边部分),而if-then-else则综合成优先编码的串接的多个多路复用器,如图的左边部分通常使用case语句要比if语句快,优先编码器的结构仅在信号的到达有先后时使用。条件赋值语句也能综合成多路复用器,而case语句仿真要比条件赋值语句快。2所有的Case应该有一个defaultcase允许空语句Default:;Writingfunctions1.在function的最后给function赋值FunctionCompareVectors;函数中避免使用全局变量否则容易引起HDL行为级仿真和门级仿真的差异。如functionByteCompareinput[15:0]Vector1input[15:0]Vector2input[7:0]Lengthbeginif(ByteSel)Verilog支持两种赋值过程赋值(procedural)和连续赋值(continuous。。过程赋值用于过程代码(initial,always,taskorfunction)中给reg和integer变量tim\realtimereal赋值,而连续赋值一般给wire变量赋值。2.Always@(敏感表)敏感表要完整,如果不完整,将会引起仿真和综合结果不一致always@(dorClr)if(Clr)q=1'b0;elseif(e)q=d;以上语句在行为级仿真时e的变化将不会使仿真器进入该进程,导致仿真结果错误3.Assign/deassign仅用于仿真加速仅对寄存器有用4.Force/release仅用于debug对寄存器和线网均有用5.避免使用Disable6.对任何reg赋值用非阻塞赋值代替阻塞赋值reg的非阻塞赋值要加单位延迟但异步复位可加可不加=与《=的区别Always@(posedgeClkornegedgeRst_)BeginIf(!Rst_)CombinatorialVsSequentialLogic1.如果一个事件持续几个时钟周期,设计时就用时序逻辑代替组合逻辑。如WireCt_24_e4;LastoverseveralclockcyclesAssignCt_24_e4=(count8bit[7:0]>=8’h24)&(count8bit[7:0]<=8’he4);那么这种设计将综合出两个8比特的加法器而且会产生毛刺,对于这样的电路,要采用时序设计,代码如下;RegCt_24_e4;Always@(poseddgeClkornegedgeRst_)BeginIf(!Rst_)Ct_24_e4<=1’b0;Elseif(count8bit[7:0]==8’he4)Ct_24_e4<=#u_dly1’b0;Elseif(count8bit[7:0]==8’h23)Ct_24_e4<=#u_dly1’b1;Esle;2.内部总线不要悬空在default状态要把它上拉或下拉WireOE_default;AssignOE_default=!(oe1|oe2|oe3);Assignbus[31:0]=oe1Data1[31:0]:oe2Data2[31:0]:oe3Data3[31:0]:oe_default32’h0000_0000:32’hzzzz_zzzz;为了保持代码的可读性,常用“`define”做常数声明2.把“`define”放在一个独立的文件中参数(parameter)必须在一个模块中定义,不要传替参数到模块(仿真测试向量例外)“`define”可以在任何地方定义,要把所有的“`define”定义在一个文件中.在编译原代码时首先要把这个文件读入,如果希望宏的作用域仅在一个模块中,就用参数来代替。对更新的内容更新要做注释2.在语法块的结尾做标记..End..End..Endfunction每一个模块都应在模块开始处做模块级的注释,参考前面标准模块头。4.在模块端口列表中出现的端口信号都应做简要的功能描述。VerilogHDL状态机的状态分配。VerilogHDL描述状态机时必须由parameter分配好状态,这与VHDL不同VHDL状态机状态可以在综合时分配产生。2.组合逻辑和时序逻辑分开用不同的进程组合逻辑包括状态译码和输出,时序逻辑则是状态寄存器的切换。3.必须包括对所有状态都处理,不能出现无法处理的状态,使状态机失控。4.Mealy机的状态和输入有关,而Moore机的状态转换和输入无关Mealy状态机的例子如下:...regCurrentState,NextState,Out1;ParameterS0=0,S1=1;always@(posedgeClkornegedgeRst_)在for-loop中包括不变的表达式浪费运算时间for(i=0;i<4;i=i+1)beginSig1=Sig2;DataOut[i]=DataIn[i];endfor-loop中第一条语句始终不变,浪费运算时间.2.资源共享问题条件算子中不存在资源共享如z=(cond)(a+b):(c+d);必须使用两个加法器;而等效的条件if-then-else语句则可以资源共享如:if(Cond)z=a+b;elsez=c+d;只要加法器的输入端复用,就可以实现加法器的共享,使用一个加法器实现3.由于组合逻辑的位置不同而引起过多的触发器综合如下面两个例子moduleCOUNT(AndBits,Clk,Rst);OutputAndbits;InputClk,Rst;RegAndBits;4.谨慎使用异步逻辑moduleCOUNT(Z,Enable,Clk,Rst);Output[2:0]Z;InputRst,Enable,Clk;reg[2:0]Z;always@(posedgeClk)beginif(Rst)beginZ<=#u_dly1'b0;endelseif(Enable==1'b1)beginIf(Z==3'd7)beginZ<=#u_dly1'b0;EndelsebeginZ<=#u_dlyZ+1'b1;endEndElse;End际的运用中要加以避免.moduleCOUNT(Z,Enable,Clk,Rst);Output[2:0]Z;InputRst,Enable,Clk;Reg[2:0]Z;对组合逻辑的描述有多种方式,其综合结果是等效的c=a&b;等效于c[3:0]=a[3:0]&b[3:0];等效于c[3]=a[3]&b[3];c[2]=a[2]&b[2];c[1]=a[1]&b[1];c[0]=a[0]&b[0];等效于for(i=0;i<=3;i=i+1)c[i]=a[i]&b[i];可以选择简洁的写法.6.考虑综合的执行时间通常会推荐将模块划分得越小越好,事实上要从实际的设计目标面积和时序要求出发好的时序规划和合适的约束条件要比电路的大小对综合时间的影响要大,要依照设计的目标来划分模块,对该模块综合约束的scripts也可以集中在该特性上,要选择合适的约束条件,过分的约束将导致漫长的综合时间最好在设计阶段就做好时序规划通过综合的约束scripts来满足时序规划。这样就能获得既满足性能的结果,又使得综合时间最省,从代码设计讲500~5000行的长度是合适的。7.避免点到点的例外所谓点到点例外Point-to-pointexception就是从一个寄存器的输出到另一个寄存器的输入的路径不能在一个周期内完成多周期路径就是其典型情况,多周期路径比较麻烦在静态时序分析中要标注为例外,这样可能会因为人为因素将其他路径错误地标注为例外,从而对该路径没有分析造成隐患避免使用多周期路径。如果确实要用,应将它放在单独一个模块,并且在代码中加以注释。8.避免伪路径(Falsepath)伪路径是那些静态时序分析(STA)认为是时序失败,而设计者认为是正确的路径。通常会人为忽略这些warning,但如果数量较多时,就可能将其他真正的问题错过了。9.避免使用Latch使用Latch必须有所记录,可以用All_registers-level_sensitive来设计中用到的Latch。不希望使用Latch时,应该对所有输入情况都对输出赋值,或者将条件赋值语句写全,如在if语句最后加一个else,case语句加defaults。当你必须使用Latch时,为了提高可测性,需要加入测试逻辑。不完整的if和case语句导致不必要的latch的产生,下面的语句中,DataOut会被综合成锁存器。如果不希望在电路中使用锁存器,它就是错误。always@(Cond)beginif(Cond)DataOut<=DataInend10.避免使用门控时钟使用门控时钟(Gatedclock)不利于移植,可能引起毛刺,带来时序问题,同时对扫描链的形成带来问题。门控钟在低功耗设计中要用到,但通常不要在模块级代码中使用。可以借助于Powercompiler来生成,或者在顶层产生。11.避免使用内部产生的时钟在设计中最好使用同步设。如果要使用内部时钟,可以考虑使用多个时钟。因为使用内部时钟的电路要加到扫描链中比较麻烦,降低了可测性,也不利于使用约束条件来综合。12.避免使用内部复位信号模块中所有的寄存器最好同时复。如果要使用内部复位,最好将其相关逻辑放在单独的模块中,这样可以提高可阅读性。13.如果确实要使用内部时钟,门控时钟,或内部的复位信号将它们放在顶层将这些信号的产生放在顶层的一个独立模块这样所有的子模块分别使用单一的时钟和复位信号一般情况下内部门控时钟可以用同步置数替代例如:moduleCOUNT(ResetEnableClkQout)moduleCOUNT(ResetEnableClkQout)inputResetEnableClkinputResetEnableClkoutput[2:0]Qoutoutput[2:0]Qoutreg[2:0]Qoutreg[2:0]QoutwireGATED_Clk=Clk&Enablealways@(posedgeClk)beginif(Reset)beginalways@(posedgeGATED_ClkorposedgeReset)Qout=1'b0beginendif(Reset)beginelseif(Enable==1'b1)beginQout=1'b0if(Qout==3'd7)beginendQout=1'b0elsebeginendif(Qout==3'd7)beginelsebeginQout=1'b0Qout=Qout+1'b1endendelsebeginendQout=Qout+1'b1endendendmoduleendendendmodule6附录Module编写示例/**\Filename﹕Author﹕Description﹕Calledby﹕RevisionHistory﹕mm/dd/yyRevisionEmail﹕Company﹕HuaweiTechnology.IncCopyright(c)1999,HuaweiTechnologyInc,Allrightreserved\**/Modulemodule_name(Output_ports,.);Module_name2Uinstance_name2(...);lk(Clk),.CLRZ(Clr),.D(Data),.Q(Qout));.Endlock(Clock),.Reset(Reset),.Qout(Qout));initialbeginClock=1'b0;Reset=1'b1;#(5*CYC)Reset=1'b0;#(5*CYC)Reset=1'b1;#(5000*CYC)$fclose(fout);$finish;endinitialbegin$shm_open("");$shm_probe("AS");fout=$fopen("");endalways#CYCClock=~Clock;//输出数据到文件always@(posedgeClock)begin$fwrite(fout,"%d%b\n",Qout,Qout);endendmodulea。在testbench中避免使用绝对的时间,如#20,#15或#(CYC+15)等,应该在文件前面使用parameter定义一些常量,使得时间的定义象#(CYC+OFF0)的形式,便于修改;b。观测结果可以输出到波形文件或数据文件生成波形文件可以用simwave观测结果比较直观而生成数据文件则既可以快速定位也可以通过编写的小程序工具对它进行进一步的处理;c。对大的设计的顶层仿真一般不要对所有信号跟踪波形文件会很大仿真时间延长可以有选择的观测一些信号。
/
本文档为【VERILOG语言编写规范】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索