《VERILOG语言编写标准规范.doc》由会员分享,可在线阅读,更多相关《VERILOG语言编写标准规范.doc(33页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、VERILOG语言编写规范1 目本规范目是提高书写代码可读性 可修改性 可重用性,优化代码综合和仿真成果,指引设计工程师使用VerilogHDL规范代码和优化电路 ,规范化公司ASIC设计输入 从而做到 1. 逻辑功能对的 2.可迅速仿真 3. 综合成果最优 如果是hardware model)4. 可读性较好。2 范畴本规范涉及Verilog HDL编码风格, 编码中应注意问题, Testbench编码等。本规范合用于Verilog model任何一级( RTL behavioral,gate_level), 也合用于出于仿真,综合或两者结合目而设计模块。3 定义Verilog HDL :
2、Verilog 硬件描述语言FSM : 有限状态机伪途径 : 静态时序分析( STA) 以为是时序失败, 而设计者以为是对的途径4 引用原则和参照资料下列原则包括条文 通过在本原则中引用而构成本原则条文 在原则出版时 所示版本均为有效 所有原则都会被修订 使用本原则各方应探讨 使用下列原则最新版本也许性Actel HDLCoding Style GuiderSun MicrosystemsRevision 1.0VerilogStyle and Coding Guidelines5 规范内容5.1 Verilog 编码风格本章节中提到Verilog编码规则和建议适应于 Verilog mode
3、l任何一级( RTL behavioral,gate_level) 也合用于出于仿真, 综合或两者结合目而设计模块。5.1.1 命名规范选取故意义信号和变量名, 对设计是十分重要。 命名包括信号或变量诸如出处, 有效状态等基本含义 下面给出某些命名规则。1. 用故意义而有效名字有效命名有时并不是规定将功能描述出来 如For ( I = 0;I 1024;I = I + 1 )MemI= #1 32b0;For 语句中循环指针I 就没必要用loop_index作为指针名。2. 用连贯缩写长名字对书写和记忆会带来不便, 甚至带来错误 采用缩写时应注意同一信号在模块中一致性。 缩写例子如下:Addr
4、 address Pntr pointerClk clockRst reset3. 用名字前加小写n表达低电平有效 高电平有效信号不得如下划线表达 短暂引擎信号建议采用高有效如 nRst, nTrdy, nIrdy nIdsel.4. 大小写原则名字普通首字符大写 ,别的小写 (但parameter,integer 定义数值名可所有用大写),两个词之间要用下划线连接(或第二个单词首字母大写)如 :Packet_addr, Data_in, Mem_wr ,Mem_ce_Or:PacketAddr, DataIn, MemWr ,MemCe5.全局信号名字中应包括信号来源某些信息如:D_addr
5、7:2 这里 D 指明了地址是解码模块(Decoder module)中地址.6. 同一信号在不同层次应保持一致性7. 自己定义常数 类型等用大写标记如:parameter CYCLE=100.8 避免使用保存字如 in out x z等不可以做为变量 端口或模块名9. 添加故意义后缀 使信号名更加明确 惯用后缀如下芯片双向信号 -xbio芯片三态输出 _xz芯片漏极开路输出 _xod芯片原始输出信号 _xo芯片原始输入信号 _xi下降沿有效寄存器 _f连到三态输出信号 _z寄存前信号 _next时钟信号 _Clk5.1.2 Modules1.顶层模块应只是内部模块间互连Verilog设计普通
6、都是层次型设计, 也就是在设计中会浮现一种或各种模块, 模块间调用在所难免。 可把设计比喻成树, 被调用模块就是树叶, 没被调用模块就是树根, 那么在这个树根模块中, 除了内部互连和模块调用外, 尽量避免再做逻辑, 如:不能再浮现对reg变量赋值等, 这样做目是为了更有效综合, 由于在顶层模块中浮现中间逻辑 ,Synopsys design compiler 就不能把子模块中逻辑综合到最优。2. 每一种模块应在开始处注明文献名 功能描述 引用模块 设计者 设计时间及版权信息等如 /* = *Filename SPI_M.vAuthor whqDescription File descripti
7、onCalled by Top module Revision History time yy-mm-ddRevision 1.0Email Copyright(c)1999, ,All right reserved/* = *3. 不要对Inpu t进行驱动, 在module 内不要存在没有驱动信号, 更不能在模块端口中浮现没有驱动输出信号, 避免在仿真或综合时产生warning, 干扰错误定位4. 每行应限制在80个字符以内 以保持代码清晰 美观和层次感一条语句占用一行 如果较长,超过80个字符 则要换行。5. 电路中调用 module 名用 Uxx 标示。 向量大小表达要清晰, 采用基于
8、名字(name_based) 调用而非基于顺序 (order_based)。Instance UInstance2(.DataOut (DOUT ),.DataIn (DIN ),.Cs_ (Cs_ );6. 用一种时钟上沿或下沿采样信号, 不能一会儿用上沿, 一会儿用下沿。 如果既要用上沿又要用下沿, 则应提成两个模块设计。 建议在顶层模块中对Clock做一非门,在层次模块中如果要用时钟下沿就可以用非门产生PosedgeClk_ , 这样好处是在整个设计中采用同一种时钟沿触发, 有助于综合。 基于时钟综合方略7. 在模块中增长注释对信号, 参量, 引脚, 模块, 函数及进程等加以阐明, 便于
9、阅读与维护。8. Module 名要用大写标示, 且应与文献名保持一致。如 Module DFF_ASYNC_RST(Reset,Clk,Data,Qout);严格芯片级模块划分只有顶层涉及IO引脚(pads), 中间层是时钟产生模块, JTAG, 芯片内核(CORE),这样便于对每个模块加以约束仿真, 对时钟也可以仔细仿真。模块输出寄存器化对所有模块输出加以寄存( 如图1) 使得输出驱动强度和输入延迟可以预测,从而使得模块综合过程更简朴- 输出驱动强度都等于平均触发器驱动强度图19.将核心途径逻辑和非核心途径逻辑放在不同模块保证DC可以对核心途径模块实现速度优化,而对非核心途径模块实行面积优
10、化 在。同一模块DC无法实现不同综合方略,将有关组合逻辑放在同一模块,有助于DC对其进行优化 由于DC普通不能越过模块边界来优化逻辑。5.1.3 Net and Register1. 一种reg变量只能在一种always语句中赋值2. 向量有效位顺序定义普通是从大数到小数尽管定义有效位顺序很自由, 但如果采用毫无规则定义势必会给作者和读代码人带来困惑 ,如 Data-4: 0, 则 LSB0-1-2-3-4MSB, 或 Data0: 4 则LSB43210MSB 这两种状况定义都不太好, 推荐Data4: 0这种格式定义。3.对net和register类型输出要做声明 在PORT中。如果一种信
11、号名没做声明 Verilog将假定它为一位宽wire变量。4. 线网各种类型。 寄存器类型。5.1.4 Expressions1. 用括号来表达执行优先级尽管操作符自身有优先顺序, 但用括号来表达优先级对读者更清晰, 更故意义。If (alpha = delta). 比下面表达更合意If (alpha = delta).(判断逻辑应是化简过后最简形式!)2. 用一种函数(function)来代替表达式多次重复如果代码中发现多次使用一种特殊表达式 ,那么就用一种函数来代替, 这样在后来版本升级时更便利, 这种概念在做行为级代码设计时同样使用, 经常使用一组描述可以写到一种任务(task)中。5.
12、1.5 IF 语句1. 向量比较时 比较向量要相等当比较向量时 verilog将对位数小向量做0 扩展以使它们长度相匹配 它自动扩展为隐式 建议采用显示扩展 这个规律同样合用于向量同常量比较Reg Abc7:0;Reg Bca3:0;.If (Abc= = 4b0,Bca)begin.If (Abc= = 8b0) begin2. 每一种If 都应有一种else 和它相相应在做硬件设计时, 常规定条件为真时执行一种动作而条件为假时执行另一动作 虽然以为条件为假不也许发生, 没有else也许会使综合出逻辑和,RTL级逻辑不同。如果条件为假时不进行任何操作, 则用一条空语句。always (Con
13、d)beginif (Cond)DataOut= DataIn;End/ Else以上语句DataOut会综合成锁存器.3. 应注意If .else if .else if .else 优先级4. 如果变量在If-else 或case 语句中做非完全赋值 则应给变量一种缺省值。即V1 = 2b00;V2 = 2b00;V3 = 2b00;If (a = = b) beginV1 = 2b01;/V3 is not assignedV2 = 2b10;EndElse if (a = = c) beginV2 = 2b10;/V1 is not assignedV3 = 2b11;EndElse
14、5.1.6 case 语句1. case语句普通综合成一级多路复用器 (图右边某些), 而if-then-else则综合成优先编码串接各种多路复用器, 如图左边某些 普通 使用case 语句要比if语句快, 优先编码器构造仅在信号到达有先后时使用。 条件赋值语句也能综合成多路复用器, 而case 语句仿真要比条件赋值语句快。2 所有Case 应当有一种default case 容许空语句Default :;5.1.7 Writing functions1. 在function最后给function赋值Function CompareVectors;/ (Vector1,Vector2,Leng
15、th)Input 199:0 Vector1,Vector2;Input 31:0 Length;/local variablesInteger i;RegEqual;Begini= 0;Equal = 1;While (iLength)& Equal) beginIf (Vector 2i != 1bx)beginIf (Vector1i!= Vector2i)Equal = 0;Else ;Endi= i+ 1;EndCompareVectors= Equal;EndEndfunction /compareVectors/比较器3. 函数中避免使用全局变量否则容易引起HDL行为级仿真和门级
16、仿真差别。如function ByteCompareinput 15:0 Vector1input 15:0 Vector2input 7:0 Lengthbeginif (ByteSel)/ compare the upper byteelse/ compare the lower byteendendfunction/ ByteCompare中使用了全局变量ByteSel 也许无旨在别处修改了, 导致错误成果 。最佳直接在端口加以定义。 ( 注意 函数与任务调用均为静态调用。)5.1.8 Assignment1. Verilog 支持两种赋值 过程赋值(procedural) 和持续赋值(
17、continuous。 过程赋值用于过程代码( initial,always,task or function) 中给reg 和 integer 变量timrealtimereal赋值, 而持续赋值普通给wire 变量赋值。2. Always (敏感表) 敏感表要完整, 如果不完整, 将会引起仿真和综合成果不一致always (d or Clr)if (Clr)q = 1b0;else if (e)q = d;以上语句在行为级仿真时e变化将不会使仿真器进入该进程,导致仿真成果错误3. Assign/deassign 仅用于仿真加速 仅对寄存器有用4. Force/release 仅用于debu
18、g 对寄存器和线网均有用5. 避免使用Disable6.对任何reg赋值用非阻塞赋值代替阻塞赋值 reg 非阻塞赋值要加单位延迟 但异步复位可加可不加 =与 =区别Always (posedge Clkor negedge Rst_)BeginIf (!Rst_)/ prioritize the “if conditions”in if statementBeginRega =0; /non_blockingassignmentRegb =0;EndElse if (Soft_rst_all)BeginRega = #u_dly0;/add unit delayRegb = #u_dly0;E
19、ndElse if (Load_init)BeginRega = #u_dly init_rega;Regb = #u_dly init_regb;EndElseBeginRega = #u_dly Rega 1;Regb = 8h24) & (count8bit7:0= 8he4);那么这种设计将综合出两个8 比特加法器 并且会产生毛刺,对于这样电路,要采用时序设计,代码如下;Reg Ct_24_e4;Always (poseddge Clk or negedge Rst_)BeginIf (!Rst_)Ct_24_e4= 1b0;Else if (count8bit7:0= = 8he4)
20、Ct_24_e4= #u_dly1b0;Else if (count8bit7:0= = 8h23)Ct_24_e4= #u_dly1b1;Esle;2. 内部总线不要悬空 在default状态 要把它上拉或下拉Wire OE_default;Assign OE_default= !(oe1| oe2| oe3);Assign bus31:0= oe1?Data131:0:oe2?Data231:0:oe3?Data331:0:oe_default?32h0000_0000 :32hzzzz_zzzz;5.1.10Macros1. 为了保持代码可读性,惯用 “define” 做常数声明2. 把
21、“define”放在一种独立文献中参数( parameter) 必要在一种模块中定义,不要传替参数到模块( 仿真测试向量例外)“define”可以在任何地方定义,要把所有“define”定义在一种文献中. 在编译原代码时一方面要把这个文献读入,如果但愿宏作用域仅在一种模块中,就用参数来代替。5.1.11Comments1. 对更新内容更新要做注释2. 在语法块结尾做标记/style 1If (OE_& (state != PENDING) begin.End / if enable = = tureand ready/style 2 - identical lableson begin and
22、 endIf (OE_& (state != PENDING) begin /drive data.End /drive data/ Comment endwith the name of the Function Calcparity /Data,ParityErr.Endfunction/ Calcparity3. 每一种模块都应在模块开始处做模块级注释, 参照前面原则模块头。4. 在模块端口列表中浮现端口信号 都应做简要功能描述。5.1.12FSM1. VerilogHDL状态机状态分派。VerilogHDL描述状态机时必要由parameter分派好状态,这与VHDL不同 VHDL状态机
23、状态可以在综合时分派产生。2. 组合逻辑和时序逻辑分开用不同进程组合逻辑涉及状态译码和输出, 时序逻辑则是状态寄存器切换。3. 必要涉及对所有状态都解决, 不能浮现无法解决状态, 使状态机失控。4. Mealy机状态和输入关于,而Moore机状态转换和输入无关Mealy 状态机例子如下:.reg CurrentState,NextState,Out1;Parameter S0=0,S1=1;always (posedge Clkor negedge Rst_)/ state vector flip-flops (sequential)if (!Reset)CurrentState= S0;el
24、seCurrentState= #u_dly NextState;always (In1or In2or CurrentState)/ output and state vector decode (combinational)case (CurrentState)S0:beginNextState= #u_dly S1;Out1= #u_dly1b0;endS1:if (In1)beginNextState= #u_dly S0;Out1= #u_dly In2;endelse beginNextState= #u_dly S1;Out1= #u_dly !In2;endendcaseend
25、module5.2 代码编写中容易浮现问题1. 在for-loop中涉及不变表达式 挥霍运算时间for (i=0;i4;i=i+1)beginSig1= Sig2;DataOuti= DataIni;endfor-loop中第一条语句始终不变,挥霍运算时间.2. 资源共享问题条件算子中不存在资源共享 如z = (cond)?(a + b) :(c + d);必要使用两个加法器;而等效条件if-then-else语句则可以资源共享 如:if (Cond)z = a + b;elsez = c + d;只要加法器输入端复用,就可以实现加法器共享,使用一种加法器实现3. 由于组合逻辑位置不同而引起过
26、多触发器综合 如下面两个例子moduleCOUNT (AndBits,Clk,Rst);Output Andbits;Input Clk,Rst;Reg AndBits;/internal regReg 2:0 Count;always (posedge Clk)beginbeginif (Rst)Count = #u_dly0;elseCount = #u_dlyCount + 1;End /end ifAndBits = #u_dly & Count;End/end alwaysendmodule在进程里变量都综合成触发器了,有4个;moduleCOUNT (AndBits,Clk,Rst
27、);Output AndBits;Input Clk,Rst;Reg AndBits;/internal regReg 2:0 Count;always (posedge Clk)begin /synchronousif (Rst)Count = #u_dly0;elseCount = #u_dly Count + 1;End/end alwaysalways (Count)begin /asynchronousAndBits= & Count;End/end alwaysEndmodule/end COUNT组合逻辑单开,只有3个触发器.4. 谨慎使用异步逻辑module COUNT (Z,
28、Enable,Clk,Rst);Output 2:0 Z;Input Rst,Enable,Clk;reg2:0 Z;always (posedge Clk)beginif (Rst)beginZ = #u_dly1b0;endelse if (Enable = 1b1) beginIf (Z = 3d7) beginZ = #u_dly1b0;Endelse beginZ = #u_dlyZ + 1b1;endEndElse ;End/end alwaysEndmodule/end COUNT是同步逻辑,而下例则使用了组合逻辑作时钟,以及异步复位.实际运用中要加以避免.module COUN
29、T (Z,Enable,Clk,Rst);Output 2:0 Z;Input Rst,Enable,Clk;Reg 2:0 Z;/internal wirewire GATED_Clk= Clk& Enable;always (posedge GATED_Clkor posedge Rst)beginif (Rst)beginZ = #u_dly1b0;endelse beginif (Z = 3d7) beginZ = #u_dly1b0;endelse beginZ = #u_dlyZ + 1b1;endEnd/end ifEnd/end alwaysEndmodule /end mod
30、ule5. 对组合逻辑描述有各种方式 ,其综合成果是等效c = a &b;等效于c3:0 = a3:0 & b3:0;等效于c3 = a3 & b3;c2 = a2 & b2;c1 = a1 & b1;c0 = a0 & b0;等效于for ( i=0;i=3;i= i+ 1)ci= ai& bi;可以选取简洁写法.6. 考虑综合执行时间普通会推荐将模块划分得越小越好, 事实上要从实际设计目的 面积和时序规定出发 好时序规划和适当约束条件要比电路大小对综合时间影响要大, 要依照设计目的来划分模块, 对该模块综合约束scripts也可以集中在该特性上, 要选取适当约束条件, 过度约束将导致漫长综
31、合时间 最佳在设计阶段就做好时序规划 通过综合约束scripts来满足时序规划 。这样就能获得既满足性能成果, 又使得综合时间最省, 从代码设计讲 5005000行长度是适当。7. 避免点到点例外所谓点到点例外 Point-to-point exception 就是从一种寄存器输出到另一种寄存器输入途径不能在一种周期内完毕 多周期途径就是其典型状况, 多周期途径比较麻烦 在静态时序分析中要标注为例外, 这样也许会由于人为因素将其她途径错误地标注为例外, 从而对该途径没有分析 导致隐患 避免使用多周期途径 。如果的确要用, 应将它放在单独一种模块, 并且在代码中加以注释。8. 避免伪途径(Fal
32、se path)伪途径是那些静态时序分析 (STA) 以为是时序失败, 而设计者以为是对的途径。 普通会人为忽视这些warning, 但如果数量较多时, 就也许将其她真正问题错过了。9. 避免使用Latch使用Latch 必要有所记录, 可以用All_registers -level_sensitive 来报告设计中用到Latch。 不但愿使用Latch时, 应当对所有输入状况都对输出赋值, 或者将条件赋值语句写全, 如在if语句最后加一种else, case语句加defaults。当你必要使用Latch时, 为了提高可测性, 需要加入测试逻辑。不完整if和case语句导致不必要latch产生
33、, 下面语句中, DataOut会被综合成锁存器。 如果不但愿在电路中使用锁存器, 它就是错误。always (Cond)beginif (Cond)DataOut= DataInend10. 避免使用门控时钟使用门控时钟(Gated clock)不利于移植, 也许引起毛刺, 带来时序问题, 同步对扫描链形成带来问题。 门控钟在低功耗设计中要用到, 但普通不要在模块级代码中使用。 可以借助于Power compiler来生成, 或者在顶层产生。11. 避免使用内部产生时钟在设计中最佳使用同步设。 如果要使用内部时钟, 可以考虑使用各种时钟。 由于使用内部时钟电路要加到扫描链中比较麻烦 ,减少了
34、可测性, 也不利于使用约束条件来综合。12. 避免使用内部复位信号模块中所有寄存器最佳同步复。 如果要使用内部复位, 最佳将其有关逻辑放在单独模块中, 这样可以提高可阅读性。13. 如果的确要使用内部时钟, 门控时钟, 或内部复位信号 将它们放在顶层将这些信号产生放在顶层一种独立模块 这样所有子模块分别使用单一时钟和复位信号 普通状况下内部门控时钟可以用同步置数代替 例如:module COUNT (Reset Enable Clk Qout) module COUNT (Reset EnableClk Qout)input Reset Enable Clk input Reset Enabl
35、e Clkoutput 2:0 Qout output 2:0 Qoutreg2:0 Qout reg2:0 Qoutwire GATED_Clk= Clk& Enable always (posedge Clk)begin if (Reset) begin always (posedge GATED_Clkor posedgeReset) Qout= 1b0begin end if (Reset) begin else if (Enable = 1b1) begin Qout= 1b0 if (Qout= 3d7) begin end Qout= 1b0else begin end if (
36、Qout= 3d7) begin else begin Qout=1b0 Qout= Qout+ 1b1end endelse begin end Qout= Qout+ 1b1 end end endmoduleend endendmodule6 附录6.1 Module 编写示例/* *Filename Author Description Called by Revision History mm/dd/yyRevision 1.0Email Company HuaweiTechnology .IncCopyright(c)1999,HuaweiTechnology Inc,All ri
37、ght reserved* */Module module_name(Output_ports,/comment ;port descriptionInput_ports,/comment ;port descriptionIo_ports,/comment ;port descripttionClk_port,/comment ;port descriptionRst_port/comment ;port description);/port declarationsOutput 31:;0 Dataout;Input 31:0 Datain;Inout Bi_dir_signal;Inpu
38、t input1,Input2;/interrnal wire/regdeclarationsWire 31:0 internal_data;Reg output_enable;/module instantiations,Self-build moduleModule_name1 Uinstance_name1(.);Module_name2 Uinstance_name2(.);/ TSC4000cellDTC12V1 (.Clk(Clk),.CLRZ(Clr),.D(Data),.Q(Qout);/continuous assignmentAssign Data_out= out_ena
39、ble? Internal_data: 32hz;/always blockAlways (input2)Begin.End/function and task definitionsFunctiom function_type function_name;Declarations_of_inputs; declarations_of_local_variables;BeginBehavirol_statement;Function_name= function_express;EndEndfunction/end function_nameEndmodule/end module_name6
40、.2 testbench编写示例下面是一种格雷码测试模块,module TB_GRAY;reg Clock;reg Reset;wire 7:0 Qout;integer fout;/输出文献指针parameter CYC= 20;GRAY DUT(.Clock(Clock),.Reset(Reset),.Qout(Qout);initialbeginClock = 1b0;Reset =1b1;#(5*CYC)Reset = 1b0;#(5*CYC)Reset = 1b1;#(5000*CYC)$fclose(fout);$finish;endinitialbegin$shm_open(GR
41、AY.shm);$shm_probe(AS);fout=$fopen(gray.dat);endalways #CYCClock = Clock;/输出数据到文献gray.datalways (posedgeClock)begin$fwrite(fout,%d %bn,Qout,Qout);endendmodulea 。在testbench 中避免使用绝对时间,如#20,#15 或#(CYC+15) 等,应当在文献前面使用parameter定义某些常量,使得时间定义象#(CYC+OFF0)形式,便于修改;b 。观测成果可以输出到波形文献GRAY.shm 或数据文献gray.dat 生成波形文献可以用simwave观测成果 比较直观 而生成数据文献则既可以迅速定位 也可以通过编写小程序工具对它进行进一步解决;c 。对大设计顶层仿真 普通不要对所有信号跟踪 波形文献会很大 仿真时间延长可以有选取观测某些信号。