Verilog-HDL 的基本概念

来源:互联网 发布:mpp打开软件 编辑:程序博客网 时间:2024/05/18 23:12
第三讲 Verilog-HDL 的基本概念
 

3.1与门的描述
      我们通过最简单的例子来认识一下Verilog-HDL 的基本用法。
      (1)模块的定义
      用Verilog-HDL 做数字电路描述,一开始所要做的就是模块(module)定义。
      所谓模块可以理解为是Verilog-HDL的基本描述单位。我们以图1为例来说明。

      这是一个二与门, 设其模块名为[AND_G2],输入为[A]和[B],输出为[F]。
      (2)模块
      模块的结构如图2 所示,module 与endmodule 总是成对出现的。此外,还有端口参数定义、寄存器定义、线网定义和行为功能调用及定义等。

      我们用Verilog-HDL 来描述图2,可以有如下两种描述方法。
            例1 二与门逻辑电路的描述
      /* AND_G2 */
      module AND_G2 (A, B, F);
            input A, B;// 输入端口定义
            output F; //输出端口定义
            and U1 ( F, A, B );
      endmodule
      或
      /* AND_G2 */
      module AND_G2 (A,B,F);
            input A, B; //输入端口定义
            output F; //输出端口定义
            assign F = A & B;
      endmodule
      例1 中的第一个例子称为门级描述方式或结构级的建模, 第二个例子称为数据流描述方式或数据流级的建模。对一个逻辑电路, 用硬件描述语言对其进行描述,或者说对其用一个模型来说明,这个过程称为建模。
      (3)门级描述方式
      例2 示出了一个门级描述方式的Verilog-HDL结构,这是一个二与门逻辑的实例。
      例2 门级描述方式
      语句1:/*AND_G2*/
      语句2 : m o d u l e
      AND_G2 (A,B,F);
      语句3: input A, B;
       // 输入端口定义
      语句4: output F;


      // 输出定义
      语句5: and U2 (F, A, B);
      语句6: endmodule
      语句1 :注释行。注释语句要写在“/*”和“*/”之间,或在行后加“//”,如语句3 和语句4。注释行不被编释,仅起注释作用。
      语句2:该语句中的“AND_G2”是所定义的模块名,模块名可用下划线“_”,但开始不可使用数字。如可以写成“AND_G2”,而不能写为“2AND”之类的形式。此外,模块名的字母可以是大写,也可以是小写,例如写为“AND_G2”或“and_g2”都可以,但“AND_G2”和“and_g2”不表示同一摸块。
模块名后紧跟着的是端口参数,即括号所包含的部分,参数间以逗号“,”来区分。在此,对参数的顺序没有规定,先后自由。在端口参数行的最后要写入分号“;”,要注意在保留字(HDL 中已规定使用的字被称为保留字,如module即为保留字。本例及全书中的保留字都用小写字母)与模块名之间要留有空格。
      语句3:描述了入口参数A 和B,由保留字input说明,参数间以逗号“,”区分,行末写入分号“;”,该行的另一种描述形式可写为
      input A;
      input B;
      语句4:描述了出口参数F,以保留字output 说明,行末写入“;”。
      端口参数的记述顺序不受限制,即可以是本例中的顺序,也可以是如下顺序:
      output F;
      input A,B;
      语句5:括号内是二与门的出口及入口参数,由于内置门实例语句规定其顺序必须是(输出,输入,输入)的形式,所以必须写成(F,A,B)的形式,最后以“;”结束该语句。
      在门级描述方式中, 调用了Verilog-HDL 所具有的内置门实例语句,例如,语句5 的and即为内置门实例语句。它调用AND 逻辑功能。其之后的“U2”称为实例名。实例名在具有行为功能的描述行里也可以省略,即可将语句5表现为如下两种形式。注意内置门实例语句要与实例名之间留有空格。
      语句6 :结束语句,与语句1 的module 相呼应,要写为“endmodule”的形式。注意行末不要加写分号“;”。
      以上讲述了门级描述方式。比较图2和例2的语法结构,我们可以初步理解端口定义和内置门实例语句的用法了。
      在Verilog-HDL 中,属于内置门实例语句的有以下8 种: and,nand,or,nor,not,xor,xnor, buf。
      (4)数据流描述方式
      还可以用数据流的描述方式来对前述同样功能的逻辑门进行描述,用数据流描述方式对一个逻辑门描述的最基本的方法就是连续使用持续赋值语句。例3给出了这种例子。
      例3数据流描述方式
      /* AND_G2 */
      module AND_G2 ( A, B, F );
      input A,B; // 输入端口定义
      output F; // 输出端口定义
      assign F = A & B;
      endmodule
      在此,仅有第5条语句与门级描述方式不同,在这里是以assign来描述电路的逻辑功能的。本例中的输出端口[F]的逻辑表达式是[A·B]。在此,用了位运算符“&”。位运算符的种类及功能有以下几种:
      ~:N O T
      :OR
      ~^:X N O R
      &:A N D
      ^:X O R
      ( 5)Verilog-HDL的语法总结
      1) 注释要用“/*”与“*/”,或在注释前用“//”。
      2) 标识符(如例1.2中的模块名和实例名均属于标识符) 可用英文及下划线“_”,标识符的开始不可用数字,对标识符的长度没有限制,大小写文字有区别。
      3) “module”与“endmodule”相呼应,成对出现。其间有端口定义,寄存器定义以及后述的线网定义等。
      4) input定义输入位号变量。
      5) output定义输出端口变量。
      6) 在门级描述方式中,调用Verilog-HDL 具有的内置门实例语句,描述顺序为“(输出,输入1,输入2,⋯⋯);”的形式。注意输出在前,输入在后。实例名也可省略。
      7) 在数据流的描述形式中,以保留
      字assign和位运算符来描述逻辑表达式。
      8) 最后写入edmodule,注意行末没有“;”。
      9) 为阅读方便,在本书中保留字全部用小写,其余均采用大写的形式。
3.2与非门的描述
      以二与非门为例, 其符号如图3 所示。在此,定义模块名为[NAND_G2],输入为[A]和[B],输出为[F]。
      图3 的门级描述方式和数据流描述方式如例4所示,在此,由于位运算的优先顺序如下(由高到底),即      ~, &, ^, ~^,

      因此要将与非的关系写成“F=~(A& B);”的形式,如果写成“F=~A &B;”的形式,则含意就会完全改变。
      例4 与非门的描述

      门级描述方式
      /* NAND_G2 */
      module NAND_G2 ( A,B,F );
      input A,B;
      output F;
      nand U4 ( F,A,B );
      endmodule
      数据流描述方式
      /* NAND_G2 */
      module NAND_G2 ( A,B,F );
      input A,B;
      output F;
      assign F = ~( A & B );
      endmodule
3.3非门的描述
      图4给出了一个非门的模型。模块名定义为[NOT_G],输入为[A],输出为[F]。

      例5 给出了门级描述方式和数据流描述方式。
      例5 非门电路的描述
      门级描述方式
      /* NOT_G */
      module NOT ( A, F );
            input A;
            output F;

            not U5 ( F, A );
      endmodule
      数据流描述方式
      /* NOT_G */
      module NOT_G ( A, F );
            input A ;
            output F;
            assign F =~A;
      endmodule
3.4或门的描述
      或门的定义如图5所示。设模块名为[OR_G2],输入变量名为[A]和[B],输出变量名为[F]。

      对该逻辑电路可用门级和数据流两种方式描述模。其描述分别示于例6。可知与前述的二与门相比,只是在此用到了“或”的逻辑表达“or”。
      例6 或门电路的描述
      门级描述方式
      /* OR_G2 */
      module OR_G2 ( A, B, F );
            input A, B;
            output F;
            or U6 ( F, A, B );
      endmodule
      数据流描述方式
      /* OR_G2 */
      module OR_G2 ( A, B, F );
            input A, B;
            output F;
            assign F = A B;
      endmodule
3.5 或非门的描述
      图6给出了一个或非门的模型,在此定义模块名为[NOR_G2],输入为[A]和[B],输出为[F]。例7给出了门级描述方式和数据流描述方式。

      例7 或非门电路的描述
      门级描述方式
      /* NOR_G2 */
      module NOR_2 ( A, B, F );
            input A, B;
            output F;
            nor U7 ( F, A, B );
      endmodule
      数据流描述方式
      /* NOR_G2 */
      module NOR_2 ( A, B, F );
            input A, B;
            output F;
            assign F =~( A B );
      endmodule
3.6缓冲器的描述
      图7给出了一个缓冲器的模型,在此定义模块名为[BUF_G],例8给出了门级描述方式和数据流描述方式。

      例8 缓冲器电路的描述
      门级描述方式
      /* BUF_G */
      module BUF_G ( A,F );
            input A ;
            output F;
            buf U8 ( F, A );
      endmodule
      数据流描述方式
      /* BUF_G */
      module BUF_G ( A, F );
            input A;
            output F;
            assign F = A;
            endmodule
3.7逻辑仿真与测试模块
      假设制作了一个电子设备,例如,一个信号放大器。那么,在放大器装完之后你一定想到以下几个问题。①这个放大器的放大倍数如何?②放大器频响特性如何?③放大器瞬态特性如何?④放大器的失真度如何?等等。为了得到这些数据,你会用各种信号发生装置去测试这个放大器,如图8(a)所示。


      同样的道理,某一功能的模块用硬件描述语言写好后,还并不能保证它的完整性,应该用某种方法对其进行测试和验证。图8(b)示出了对硬件描述语言的验证方法。与放大器相对应,具有某种功能的硬件描述语言模块要接受来自验证测试程序的信息,然后将输出信息传递给显示模块。
      验证程序是要产生模拟的激励波形并将此激励加于功能模块, 模块的输出信息在仿真软件的控制下显示出来。验证程序也称为测试程序、测试文件、顶层模块或测试模块,本讲座中称为测试模块。
      下面是一个二与门逻辑的测试模块。
      例9 二与门逻辑模块的测试模块
      01 /* AND_G2_TEST */
      02 `timescale 1ns/1ns
      // 将仿真的单位设定为 1ns
      03 module AND_G2_TEST;
      04 reg A, B;
      // 寄存器定义 输入端口定义
      05 wire F;
      // 线网定义 输出端口定义
      06 AND_G2 AND_G2 ( A,B, F); // 底层模块名、实例名及参数。
      07 initial begin
      08 A = 0; B = 0;
      09 #100 A = 1;
      10 #100 A = 0; B = 1;
      11 #100 A = 1;
      12 #200 $finish;
      13 end
      14 endmodule
      为阅读方便,在上述程序中增加了行标00-14。
      (1)寄存器定义
      被测试模块的输入端口定义为 reg型,如第04 行所示。其使用法与 input和 output 相同。
      (2)线网定义
      被测试模块的输出端口定义为 wire型,如第05行所示。其使用法也与input和output相同。
      (3)底层模块的调用所谓底层模块即被测试模块,可由测试模块调用,如例9 的第06 行。在该行中,依次出现了AND_G2、AND_G2和( A, B, F )。其中,第一个AND_G2为底层模块名,第二个AND_G2 为实例名,而( A, B, F )为参数定义。即在Verilog-HDL 中,调用底层模块的语法结构为:
      底层模块名 实例名 参数定义

      需要注意,在本例中,底层模块的模块名要与3.1.1中所述的模块名一致。实例名可以自由起名,在此使用了相同的名字AND_G2 。
      参数的定义也很重要。在参数定义中,有“A、B、F ”,相应地在底层模块AND_G2 中也有“A 、B 、F”,它与测试模块的“A 、B、F”一一呼应,形成了一个实体,如图9 所示。
      由于这种原因,它们的参数记述顺序也是很重要的。如双方都应是“A,B, F”和“A, B, F”;而不能是“A, B, F”和“B,A,F”。不过,由于这种结合只是测试和底层模块间端口的结合,所以两个模块的端口名不一定一致。例如,在例9 中,可将04 行写为“reg INA, INB;”,同时将 06 行写为“AND_G2 AND_G2( INA, INB, F_OUT );”,而底层模块不做任何变更。
      (4)输入端口波形的描述
      例9中 08 行的保留字“initial”以下顺序描述了波形的变化情况,所描述的内容在“begin”和“end”之间。注意在“initial”、“begin”、“end”之后没有“;”。
      本例所要仿真的是一个二与门逻辑电路,输入端口为 A、B。这里,我们令A 和B 作如下变化:
      开始 A=“0”,B=“0”
      100ns 后 A=“1”,B=“0”
      200ns 后 A=“0”,B=“1”
      300ns 后 A=“1”,B=“1”
      由例9 中 02 行编译器指令,它将延时单位与实际时间相关连。仿真的结束由保留字 $finish描述。在本例中,仿真的时间长度总共为500ns。另外,在 09行之后,以“#100”表示100ns 的延时。例9单独为一个文件,作为仿真的输入文件之一。
      (5) 二与门的仿真结果
      在输入的作用下,输出就会有响应,在这里的响应也就是仿真结果。图10示出了二与门的仿真结果,它清楚地表明了输入与输出间的逻辑关系。关于仿真软件的使用方法,将在后续讲座中予以解说。

原创粉丝点击