0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Verilog编写规范

FPGA设计论坛 ? 来源:FPGA设计论坛 ? 2025-04-11 09:36 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

1.命名规则

用有意义而有效的名字

有效的命名有时并不是要求将功能描述出来,如:

for(i =0;i 

用连贯的缩写
采用缩写时应该主义同一信号在模块中的一致性.如:

 Addraddress  Pntrpointer   Clkclock  Rstreset

用最右边的字符下划线代表低电平有效,高电平有效的信号不得以下划线表示,短暂的有效信号建议采用高电平有效.如:

  Rst_   Trdy_   Irdy_

大小写原则
名字一般首字符大写,其余小写(但是parameter/integer定义的数值名可以全部大写),两个单词之间用下划线连接.如:

  Data_in  Mem_wr   Rd_req   Sensor_ctrl

全局信号名中应包含信号来源的信息.

如:D_addr[7:2],这里的"D"指明了地址是解码模块(Decoder module)的地址.

同一信号在不同层次应保持一致性

自己定义的常数和类型等用大写表示.如:

  parameter CYCLE=100;

避免使用保留字

如:in,out,x,z等不能够作为变量,端口或模块名

添加有意义的后缀,使信号名更加明确,常用的后缀有:

 _Clk  时钟信号  _next 寄存前的信号  _z   连到三态输出的信号  _f   下降沿有效的寄存器  _xi  芯片原始输入信号  _xo  芯片原始输出信号  _xod  芯片的漏极开路输出  _xz  芯片的三态输出   -xbio  芯片的双向信号

2.Modules

顶层模块应知识内部模块间的互联

Verilog设计一般都是层次性的设计,也就是在设计中会出现一个或多个模块,模块间的调用在所难免.可把设计比喻成树,被调用的模块就是输液,没被调用的模块就是树根,那么在这个树根模块中,除了内部的互联和模块的调用外,尽量避免再做逻辑,如不能再出现对reg变量赋值等.这样做的目的是为了更有效的综合,因为在顶层模块VS出现中间逻辑,Synopsys的Design Compiler就不能把子模块中的逻辑综合到最优.

每个模块应该在开始处注明文件名,功能描述,引用模块,设计者,设计时间,以及版权信息等.如:

 /*==============================================================================================*/    Filename      :  RX_MUX.v     Author       :  Dongyi Lin     Description     :      Called by      : Top module     Revision History  : 22-05-27    Revision      : 1.0    Email       :  lindongyi@163.com    Company      :  Hunan Institute of Advanced SensingandInformation Technology,                 Xiangtan Univeristy    Copyright     : 2022, Xiangtan University, All right reserved  /*==============================================================================================*/

不要对Input进行驱动,在module内不要存在没有驱动的信号,更不能在端口模块出现没有驱动的输出信号,避免再仿真或综合时产生warning,干扰错误定位.

每行应限制在80个字符以内,以保持代码的清晰,没关和层次感.

一条语句占用一行,如果超过80个字符则要换行.

电路中调用的module名用Uxx表示.向量大小要表示清晰,采用基于名字的(name_based)调用,而非基于顺序的(order_based).

Instance  Uinstance2(         .DataOut    (DOUT   ),         .DataIn     (DIN    ),         .Cs_      (Cs_),       );

时钟的上升沿或下降沿采样信号,不能一会上升沿,一会用下降沿.如果既要用上升沿又要用下降沿,应该分成两个模块设计.建议在顶层模块中对Clock做一个not门,
在层次模块中如果要用时钟下降沿就可以用not门产生的Posedge Clk_,这样的好处是在整个设计中采用同一种时钟出发,有利于综合.

在模块中增加注释.

对信号,参量,引脚,模块,函数及进程等加以说明,便于阅读与维护.

Module名称要用大写表示,且应该与文件名保持一致.如:

  module DFF_ADSYNC_RST(              Reset,              Clk,              Data,              Qout   );

要严格芯片级模块的划分

只有顶层包括IO引脚(pads),中间层是时钟产生模块,JTAG,芯片的内核(CORE),这样便于对每个模块加以约束仿真,对时钟也可以仔细仿真.

模块输出寄存器化

对所有的模块的数据加以寄存,使得输出的驱动强度和输入的延迟可以预测,从而使得模块的综合过程更简单.

3.Net and Register

一个reg变量只能在一个always语句中赋值

向量有效位顺序一边为从大到小
推荐Data[4:0]这种格式的定义.

对net和register类型的数据要做声明(在PORT中).

4.Expressions

用括号表示执行的优先级,对读者更情绪,更有意义,如:

 if(alpha =delta)...就不如下面的更好  if((alpha =delta))

用函数(function)来代替表达式的多次重复

这样在以后的版本升级时更便利,而且经常使用的一组描述可以写到一个任务(task)中

5.IF语句

向量比较时,比较的向量要相等

在向量比较时,verilog将位数小的向量做0扩展以使得他们的长度相匹配,它的自动扩展是隐式的.建议采用显式扩展.如:

  reg Abc[7:0];   reg Bca[3:0];   ......  if(Abc == {4'b0,Bca})begin   ......  if(Abc ==8'b0)begin

每一个if都应该有一个else与之对应
没有else可能会使得综合出的逻辑和RTL级的逻辑不同,如果条件为假时不尽兴任何操作,则使用一条空语句,如:

  always@(Cond)begin    if(Cond)      DataOut <= DataIn; ? ? end ? ?//以上语句DataOut会综合出锁存器.

如果变量在if-else语句或case语句中没有被完全赋值,则应该提前给变量一个缺省值,即:

  V1 =2'b00;   V2 =2'b00;   V3 =2'b00; //给V1,V2,V3缺省值,在后面赋值变量时有一个默认值在  if(a == b)begin    V1 =2'b01;     V2 =2'b10; //V3isnotassigned, so thedefaultvalueofV3is2'b00;  end  elseif(a == c)begin    V2 =2'b10;     V3 =2'b11; //V1isnotassigned, so thedefaultvalueofV1is2'b00;  end  ...

6.case语句

case语句通常被综合为一级多路复用器,而if-then-else语句则综合为优先编码的串接的多个多路复用器.通常case语句比if语句快,有限编码结果在信号到达时有先后.case语句仿真比条件语句快.

所有的case语句都应该有一个default case,且允许空语句出现如:

default:;

7.Function

在function的最后给function赋值,如:

 functionCompareVectors;  input[199:0]Vector1;  input[199:0]Vector2;  input[31:0]Length;  //local variables  integeri;  regEqual;     begin    i =0;     Equal =1;//给Equal赋初值    while((i < Length)&& Equal)begin? ? ? ? ? ? ?if(Vector2[i] !==?1'bx)begin? ? ? ? ? ? ? ? ?if(Vector1[i] !== Vector2[i])  ? ? ? ? ? ? ? ? ? ?Equal =?0; ? ? ? ? ? ? ? ?else; ? ? ? ? ? ?end? ? ? ? ? ? ?i = i +?1; ? ? ? ?end? ? ? ? ?CompareVectors = Equal;?//赋值放在function的最后? ? ?endendfunction

在function中避免使用全局变量

否则容易引起HDL行为及仿真和门级仿真的差异.如:

 functionByteCompare;    input [15:0] Vector1;    input [15:0] Vector2;    input [7:0]  Length;    begin      if(ByteSel)//ByteSel是全局变量,如果在其他位置无意修改了,可能导致函数结果错误,            //所以最好在端口加以定义        ...      else        ...    end  endfunction

注意,函数与任务的调用均为静态调用.

8.Assignment

Verilog有两种赋值方式:过程赋值(procedural)和连续赋值(continuous).过程复制用于过程代码(initial,always,task,function)中给reg和integer变量,time ealtime eal复制,而连续赋值一般给wire变量赋值.

always@(敏感表),敏感表要完整,如果不完整,将会引起仿真和综合结果不一致,如:

 always@(dorClr)    if(Clr)       q =1'b0;    elseif(e)       q = d;  //以上语句在行为及仿真时e的变化不会使仿真器进入该always块,导致仿真结果错误.

assign/deassign仅用于仿真加速,仅对寄存器有用.

force/release仅用于debug,对寄存器和线网型都有用.

避免使用disable

对任何reg赋值,都用非阻塞赋值(<=)代替阻塞赋值(=),reg的非阻塞赋值要加单位延迟,但异步复位可加可不加.如:

  always@(posedge Clk or negedge Rst_)begin    if(!Rst_)begin      Rega <=?0; ?//non_blocking assignment ? ? ? ? ? ? Regb <=?0; ? ? ? ?end? ? ? ? ?else?if(Soft_rst_all)begin? ? ? ? ? ? ?Rega <=?#u_dly ?0; ?//add unit delay? ? ? ? ? ? ?Regb <=?#u_dly ?0;? ? ? ? ?end? ? ? ? ?else?if(Load_init)begin? ? ? ? ? ? ?Rega <=?#u_dly ?init_rega;? ? ? ? ? ? ?Regb <=?#u_dly ?init_rega;? ? ? ? ?end? ? ? ? ?else?begin? ? ? ? ? ? ?Rega <=?#u_dly ?Rega << 1; ? ?? ? ? ? ? ? ?Rega <=?#u_dly ?St_1; ? ?? ? ? ? ?end? ? ?end?//end?Rega,Regb assignment

9.Combinatorial vs Sequential Logic

如果一个事件持续几个时钟周期,设计时就用时序逻辑代替组合逻辑. 如:

 wireCt_24_e4; //Ct_24_e4 last over several clock cycles  assign Ct_24_e4 = (count8bit[7:0] >=8'h24) & (count8bit[7:0] <=?8'he4);

这种设计将综合处两个8bit加法器,而且会产生毛刺,对于这种电路,要采用时序设计,代码如下:

 regCt_24_e4;    always@(posedgeClkornegedgeRst_)begin    if(!Rst_)       Ct_24_e4 <=?1'b0; ? ? ? ?else?if(count8bit[7:0] >8'he4)       Ct_24_e4 <= #u_dly ?1'b0; ? ? ? ?else?if(count8bit[7:0] >8'h23)       Ct_24_e4 <= #u_dly ?1'b1; ? ? ? ?else? ? ; ? ?end

内部总线不要悬空.在default状态,要把他上拉或下拉.

 wire  OE_default;  assign OE_default = !(oe1 | oe2 | oe3);  assign bus[31:0] = oe1 ? Data1[31:0]:             oe2 ? Data2[31:0]:             oe3 ? Data3[31:0]:             OE_default ?32'h0000_0000://如果bus不等于oe1,oe2,oe3中的任何一个,                          //若等于OE_default,则bus为32'h0即拉低,否则拉高为高阻态.            32'hzzzz_zzzz;

10.Macros 宏指令

为了保持代码的可读性常用`define做常数声明

把`define放在一个独立的文件中

参数(parameter)必须在一个模块中定义,不要传递参数到模块(仿真测试向量例外);

define可以在任何地方定义,要把所有的define定义在一个文件中(极少的一个两个define就不用了吧),在编译源代码时首先把这个文件读入.

如果希望宏的作用于仅在一个模块中,就用参数来代替.

11.Comments

对更新的内容要做注释

在语法块的结尾做标记

每一个模块都应该在模块开始处做模块级的注释(参考前面的标准模块头)

在端口列表中出现的端口信号,都应该做简要的功能描述.

12.FSM 状态机

状态机的状态分配

Verilog描述状态机时必须有parameter分配好状态.

组合逻辑和时序逻辑分开用不同的进程

组合逻辑包括状态译码和输出,时序逻辑则是状态寄存器的切换

必须对所有状态都处理,不能出现无法处理的状态,使状态机时空

Mealy状态机输出不仅取决于当前状态,还与输入有关;Moore状态机输出仅与当前状态有关.

Mealy状态机的例子如下:

  ...  regCurrentState,NextState,Out1;  parameterS0 =0, S1 =1;  always@(posedgeClkornegedgeRst_)    if(!Rst_)       CurrentState <= S0; ? ? ? ?else? ? ? ? ? ? ?CurrentState <= #u_dly NextState; ? ?always@(In1?or?In2?or?CurrentState) ? ? ? ?case(CurrentState) ? ? ? ? ? ? S0:begin? ? ? ? ? ? ? ? ?NextState <= #u_dly S1; ? ? ? ? ? ? ? ? Out1 <= #u_dly?1'b0; ? ? ? ? ? ?end? ? ? ? ? ? ?S1:begin? ? ? ? ? ? ? ? ?if(In1)begin? ? ? ? ? ? ? ? ? ? ?NextState <= #u_dly S0; ? ? ? ? ? ? ? ? ? ? Out1 <= #u_dly !In2; ? ? ? ? ? ? ? ?end? ? ? ? ? ? ?end? ? ? ? ?endcase

13.Module 编写示例

/*==============================================================================================*/  Filename      :  module_name.v  Author       :  Dongyi Lin   Description     :    Called by      :  Topmodule  Revision History  : 22-05-27  Revision      : 1.0  Email        :  lindongyi@163.com  Company       :  Hunan Institute of Advanced SensingandInformation Technology,               Xiangtan Univeristy   Copyright      : 2022, Xiangtan University, All right reserved/*==============================================================================================*/modulemodule_name(           Output_ports,   //comment:port description          Input_ports,    //comment:port description          Io_ports,     //comment:port description          Clk_port,     //comment:port description          Rst_port      //comment:port description);//port declarations  output   [31:0]   Dataout;  input   [31:0]   Datain;  inout         Bi_dir_siginal;  input         input1;               input2;     //interrnal wire/reg declarations  wire    [31:0]   internal_data;  reg          output_enable;     //module instantiations, Self-build module  module_name1 Uinstance_name1(                  .port1(...);                  .port2(...);   );     module_name2 Uinstance_name2(                  .port1(...);                  .port2(...);   );    //TSC4000 cell  DTC12V1(      .Clk(Clk),      .CLRZ(Clr),      .D(Data),      .Q(Qout)   );//always block  always@(input2)begin    ...  end//function and task definitions  function[function_type] function_name;     declarations_of_inputs;     [declarations_of_local_variables];    begin      behavirol_statement;       function_name = function_express;    end  endfunction  endmodule

14.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)   );   initial begin     Clock = 1'b0;     Reset = 1'b1;    #(5*CYC) Reset = 1'b0;    #(5*CYC) Reset = 1'b1;    #(5000*CYC);     $fclose(fout);     $finish;   end   initial begin     $shm_open("GRAY.shm");     $shm_probe("AS");     fout = $fopen("gray.dat");   end   always#(CYC)Clock = ~Clock;   //输出数据到文件gray.dat   always@(posedge Clock)begin     $fwrite(fout,"%d %b
", Qout, Qout);   end endmodule

在testbench中避免使用绝对的时间,如#20,#15或#(CYC + 15)等,应该在文件前端使用parameter定义一些常量,使得时间的定义像#(CYC + OFF0)这样的形式,便于修改;

观测结果可以输出到波形文件GRAY.shm,或数据文件gray.dat.生成波形文件可以使用simwave或gtkwave观测结果,比较直观;而生成数据文件则既可以快速定位,也可以通过编写的小程序工具对它进行进一步的处理;

对大的设计的顶层方针,一般不要对所有信号进行跟踪,大的设计波形文件会很大,仿真时间也会延长,可以有选择的观测一些信号.

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模块
    +关注

    关注

    7

    文章

    2790

    浏览量

    50681
  • Verilog
    +关注

    关注

    29

    文章

    1367

    浏览量

    112417
  • 波形
    +关注

    关注

    3

    文章

    390

    浏览量

    32408

原文标题:Verilog编写规范

文章出处:【微信号:gh_9d70b445f494,微信公众号:FPGA设计论坛】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【分享】verilog代码书写规范

    FPGA verilog代码书写规范,很好的借鉴
    发表于 05-21 11:36

    Verilog HDL代码书写规范

    :① 逻辑功能正确,②可快速仿真,③ 综合结果最优(如果是hardware model),④可读性较好。2. 范围本规范涉及Verilog HDL编码风格,编码中应注意的问题, Testbench的编码
    发表于 12-08 14:36

    Verilog代码书写规范

    Verilog代码书写规范规范的目的是提高书写代码的可读性、可修改性、可重用性,优化代码综合和仿真的结果,指导设计工程师使用
    发表于 04-15 09:47 ?106次下载

    verilog代码规范

    verilog代码规范,学会写代码还不行,我们需要更加的规范
    发表于 03-25 14:43 ?24次下载

    华为_VERILOG语言编写规范

    verilog代码规范,学会写代码还不行,我们需要更加的规范
    发表于 03-25 14:36 ?35次下载

    Verilog程序编写规范

    适合verilog初学者的教程,可以好好参考学习。
    发表于 03-25 14:06 ?12次下载

    Verilog编写的基于SPARTAN板的VGA接口显示程序

    Xilinx FPGA工程例子源码:Verilog编写的基于SPARTAN板的VGA接口显示程序
    发表于 06-07 14:54 ?10次下载

    Verilog编写的信道估计

    Xilinx FPGA工程例子源码:Verilog编写的信道估计
    发表于 06-07 14:54 ?38次下载

    华为的verilog编码规范

    华为的verilog编码规范
    发表于 11-01 08:41 ?41次下载
    华为的<b class='flag-5'>verilog</b>编码<b class='flag-5'>规范</b>

    Verilog程序编写规范

    在实际工作中,许多公司对Verilog程序编写规范都有要求。在公司内部统一Verilog程序编写规范
    的头像 发表于 09-15 09:35 ?4382次阅读

    verilog语言编写规范

    规范的目的是提高书写代码的可读性 可修改性 可重用性 优化代码综合和仿真的结 果 指导设计工程师使用VerilogHDL规范代码和优化电路 规范化公司的ASIC设计输入从而做到。
    的头像 发表于 11-23 17:28 ?1557次阅读

    基于verilog编写99秒计数器

    Verilog语言编写,通过模块化设计的99秒技术器
    发表于 02-16 16:16 ?0次下载

    如何使用参数化编写可重用的verilog代码

    我们将介绍如何使用verilog参数和generate语句来编写可重用的verilog 代码。 与大多数编程语言一样,我们应该尝试使尽可能多的代码可重用。这使我们能够减少未来项目的开发时间
    的头像 发表于 05-11 15:59 ?1511次阅读

    FPGA的Verilog代码编写规范

      注:以R起头的是对编写Verilog代码的IP设计者所做的强制性规定,以G起头的条款是建议采用的规范。每个设计者遵守本规范可锻炼命名规范
    的头像 发表于 08-15 16:23 ?2984次阅读

    IC设计之Verilog代码规范

    Verilog规范对于一个好的IC设计至关重要。
    的头像 发表于 08-17 10:14 ?2106次阅读
    IC设计之<b class='flag-5'>Verilog</b>代码<b class='flag-5'>规范</b>