小舍YZ 发表于 2017-4-6 10:49:49

2.5.2 模块命名规则

HDL语言的模块类似于C语言中的函数,可采用C语言函数的大多数规则。模块的命名应该尽量用英文表达出其完成的功能。遵循动宾结构的命名法则,函数名中动词在前,并在命名前加入函数的前缀,函数名的长度一般不少于2个字母。HDL模块的命名还需要考虑以下情况:

1.模块的命名规则

在系统设计阶段应该为每个模块进行命名。命名的方法是,将模块英文名称的各个单词首字母组合起来,形成3到5个字符的缩写。若模块的英文名只有一个单词,可取该单词的前3个字母。各模块的命名以3个字母为宜。例如:

Arithmatic Logical Unit模块,命名为ALU。
Data Memory Interface模块,命名为DMI。
Decoder模块,命名为DEC。

2.模块之间接口信号的命名

所有变量命名分为两个部分,第一部分表明数据方向,其中数据发出方在前,数据接收方在后,第二部分为数据名称。两部分之间用下划线隔离开。第一部分全部大写,第二部分所有具有明确意义的英文名全部拼写或缩写的第一个字母大写,其余部分小写。举例:

      wire CPUMMU_WrReq;

下划线左边是第一部分,代表数据方向是从CPU模块发向存储器管理单元模块(MMU)。下划线右边Wr为Write的缩写,Req是Request的缩写。两个缩写的第一个字母都大写,便于理解。整个变量连起来的意思就是CPU发送给MMU的写请求信号。模块上下层次间信号的命名也遵循本规定。若某个信号从一个模块传递到多个模块,其命名应视信号的主要路径而定。

3.模块内部信号:

模块内部的信号由几个单词连接而成,缩写要求能基本表明本单词的含义;单词除常用的缩写方法外(如:Clock->Clk, Write->Wr, Read->Rd等),一律取该单词的前几个字母( 如:Frequency->Freq, Variable->Var 等);每个缩写单词的第一个字母大写;若遇两个大写字母相邻,中间添加一个下划线(如DivN_Cntr);举例:

      SdramWrEn_n;
      FlashAddrLatchEn;

小舍YZ 发表于 2017-4-6 10:51:10

2.5.3 代码格式规范

1. 分节书写格式

各节之间加1到多行空格。如每个always,initial语句都是一节。每节基本上完成一个特定的功能,即用于描述某几个信号的产生。在每节之前有几行注释对该节代码加以描述,至少列出本节中所描述信号的含义。
      
行首不要使用空格来对齐,而是用Tab键,Tab键的宽度设为4个字符宽度。行尾不要有多余的空格。

2. 注释的规范

使用//进行的注释行以分号结束;使用/* */进行的注释,/*和*/各占用一行,并且顶头;例如:

// Edge detector used to synchronize the input signal;
对于函数,应该从“功能”,“参数”,“返回值”、“主要思路”、“调用方法”、“日期”六个方面用如下格式注释:
// 程序说明开始
// ================================================================//
// 功能: 完成两个输入数的相加。
// 参数: strByDelete,strToDelete
// 输入参数
// 输出参数
// 主要思路:本算法主要采用2级流水线完成相加
// 日期:起始日期,如:2007/8/21.9:40--2007/8/23.21:45
// 版本:
// 程序编写人员:
// 程序调试记录:
// ================================================================//
// 模块说明结束
此外,在注释说明中,需要注意以下细节:
•        在注释中应该详细说明模块的主要实现思路,特别要注明自己的一些想法,如果有必要则应该写明对想法产生的来由。
•        在注释中详细注明函数的适用方法,对于输入参数的要求以及输出数据的格式。
•        在注释中要强调调用时的危险方面,可能出错的地方。
•        对日期的注释要求记录从开始编写模块到模块测试结束之间的日期。
•        对模块注释开始到模块命名之间应该有一组用来标识的特殊字符串。如果算法比较复杂,或算法中的变量定义与位置有关,则要求对变量的定义进行图解。对难以理解的算法能图解尽量图解。
3.空格的使用:

不同变量,以及变量与符号、变量与括号之间都应当保留一个空格。Verilog关键字与其它任何字符串之间都应当保留一个空格。如:

      always @ ( ...... )

使用大括号和小括号时,前括号的后边和后括号的前边应当留有一个空格。逻辑运算符、算术运算符、比较运算符等运算符的两侧各留一个空格,与变量分隔开来;单操作数运算符例外,直接位于操作数前,不使用空格。使用//进行的注释,在//后应当有一个空格;注释行的末尾不要有多余的空格。例:

assign SramAddrBus = { AddrBus, AddrBus };
assign DivCntr = DivCntr + 4'b0001;
assign Result = ~Operand;

4.begin…end的书写规范

同一个层次的所有语句左端对齐;initial、always等语句块的begin关键词跟在本行的末尾,相应的end关键词与initial、always对齐;这样做的好处是避免因begin独占一行而造成行数太多;如:

always @ ( posedge SysClk or negedge SysRst ) begin
         if( !SysRst ) DataOut <= 4'b0000;
         else if( LdEn ) begin
                  DataOut <= DataIn;
                  End
         else
                   DataOut <= DataOut + 4'b0001;
end

不同层次之间的语句使用Tab键进行缩进,每加深一层缩进一个Tab;在endmodule,endtask,endcase等标记一个代码块结束的关键词后面要加上一行注释说明这个代码块的名称。

小舍YZ 发表于 2017-4-6 10:51:36

2.5.4 模块调用规范
在Verilog中,有两种模块调用的方法,一种是位置映射法,严格按照模块定义的端口顺序来连接,不用注明原模块定义时规定的端口名,其语法为:

模块名 (连接端口1信号名, 连接端口2信号名, 连接端口3信号名,…);

另一种为信号映射法,即利用“.”符号,表明原模块定义时的端口名,其语法为:

模块名 (.端口1信号名(连接端口1信号名),
               .端口2信号名(连接端口2信号名),
               .端口3信号名(连接端口3信号名),…);

显然,信号映射法同时将信号名和被引用端口名列出来,不必严格遵守端口顺序,不仅降低了代码易错性,还提高了程序的可读性和可移植性。因此,在良好的代码中,严禁使用位置调用法,全部采用信号映射法。

小舍YZ 发表于 2017-4-6 10:52:23

本帖最后由 小舍YZ 于 2017-4-7 14:32 编辑

第6节 Verilog常用程序示例

2.6.1 Verilog基本模块

1.触发器的Verilog实现

时序电路是高速电路的主要应用类型,其特点是任意时刻电路产生的稳定输出不仅与当前的输入有关,而且还与电路过去时刻的输入有关。时序电路的基本单元就是触发器。下面介绍几种常见同步触发器的Verilog实现。
•        同步RS触发器
RS触发器分为同步触发器和异步触发器,二者的区别在于同步触发器有一个时钟端clk,只有在时钟端的信号上升(正触发)或下降(负触发)时,触发器的输出才会发生变化。下面以正触发为例,给出其Verilog代码实现。

例2-15 正触发型同步RS触发器的Verilog实现。

module sy_rs_ff (clk, r, s, q, qb);
      input clk, r, s;
      output q, qb;
      reg q;

      assign qb = ~ q;
      always @(posedge clk) begin
               case({r, s})
                        2'b00: q <= 0;
                        2'b01: q <= 1;
                        2'b10: q <= 0;
                        2'b11: q <= 1'bx;
               endcase
         end
endmodule

上述程序经过综合Synplify Pro后,其RTL级结构如图2-2所示。

图2-2 同步RS触发器的RTL结构图




小舍YZ 发表于 2017-4-7 14:35:30

在ModelSim 6.2b中完成仿真,其结果如图2-3所示 。

图2-3 同步RS触发器的仿真结果示意图

小舍YZ 发表于 2017-4-7 14:36:32

•        同步T触发器
T触发器也分为同步触发器和异步触发器,二者的区别在于同步T触发器多了一个时钟端。同步T触发器的逻辑功能为:当时钟clk沿到来时,如果T=0,则触发器状态保持不变;否则,触发器输出端反转。R为复位端,当其为高电平时,输出Q与时钟无关,Q=0。

例2-16 同步T触发器的Verilog实现。

module sy_t_ff(clk, r, t, q, qb);
      input clk, r, t;
      output q, qb;
      reg q;

      assign qb = ~q;
      always @(posedge clk) begin
               if(r)
                   q <= 0;
               else
                  q <= ~q;
      end
endmodule

上述程序经过综合Synplify Pro后,其RTL级结构如图2-4所示。

图2-4 同步T触发器电路的RTL结构图

小舍YZ 发表于 2017-4-7 14:37:18

在ModelSim 6.2b中完成仿真,其结果如图2-5所示。

图2-5 同步T触发器的仿真结果示意图

小舍YZ 发表于 2017-4-7 14:38:01

•       同步D触发器
同步D触发器的功能为: D输入只能在时序信号clk的沿变化时才能被写入到存储器中,替换以前的值,常用于数据延迟以及数据存储模块中。

例2-17 同步D触发器的Verilog实现。

module sy_d_ff(clk, d, q, qb);
      input clk, d;
      output q, qb;
      reg q;

      assign qb = ~q;
      always @(posedge clk) begin
               q <= d;
      end
endmodule

上述程序经过综合Synplify Pro后,其RTL级结构如图2-6所示。

图2-6 同步D触发器的RTL结构图

小舍YZ 发表于 2017-4-7 14:38:41

在ModelSim 6.2b中完成仿真,其结果如图2-7所示。

图2-7 同步D触发器的仿真结果示意图

小舍YZ 发表于 2017-4-7 14:39:50

•        同步JK触发器
JK触发器是在RS触发器的基础上发展而来的,常用于实现计数器。当clk=0时,触发器不工作,处于保持状态。当时钟clk=1时,触发器的功能如下:当JK为00、01以及10时实现RS触发器的功能;当JK为11时实现T触发器的功能。

例2-18 同步JK触发器的Verilog实现。

module sy_jk_ff(clk, j, k, q, qb);
      input clk, i, k;
      output q, qb;
      reg q;

      assign qb = ~q;
      always @(posedge clk) begin
                case({j, k})
                           2'b00: q <= q;
                           2'b01: q <= 0;
                           2'b10: q <= 1;
                           2'b11: q <= ~q;
               endcase
      end
endmodule

上述程序经过综合Synplify Pro后,其RTL级结构如图2-8所示。

图2-8 同步JK触发器的RTL结构图
页: 1 2 3 4 5 6 [7] 8 9 10 11 12
查看完整版本: FPGA开发 实用内容