{ id : 'top-progress-bar', // 请勿修改该值 color : '#77b6ff', height : '2px', duration: 0.2, }

Verilog门级描述

前言


门级建模比较接近电路底层,设计时主要考虑使用到了哪些门,然后按照一定的顺序连接线组成一个大的电路,所以注重的是门的使用,关键的语法在于门的实例化引用。

一个完整的门级描述实例一般包含模块定义、端口声明,内部连线声明,门级调用等几个部分。

我们按照例子进行分析:

点击查看代码
module logic_gates(oY,iA,iB,iC);
  output oY;
  input iA,iB,iC;
  and(and1,iA,iB);
  and(and2,iA,iC);
  or(oY,and1,and2);
endmodule

模块定义


关键词


模块定义以关键字module开始,以关键字endmodule结束,在这两个关键字之间的代码被识别为一个模块,描述一个具有某种基本功能的电路模型

语法格式如下:

module  模块名(端口1,端口2,端口3,……);//端口列表
………………                        //模块部分    
endmodule

与C语言的函数定义类似,用来描述"函数"的界限

除了部分宏定义语法之外,其余的所有verilog代码都要写在module,与endmodule之间。

不严谨的来说,我们可以把一个模块类比为C语言的一个函数,也正因为如此,我们可以在一个.v文件中写许多moduleendmodule,即一个文件中可以有很多函数。但为了便于管理,一般情况下一个.v文件只写一个moduleendmodule


模块名


在关键词module之后,还要跟上一个字符串作为本模块的名字,以空格隔开,称之为标识符.

标识符(identifier)可以是任意一组字母、数字、$ 符号和 _(下划线)符号的合,但标识符的第一个字符必须是字母或者下划线,不能以数字或者美元符开始,标识符不能与系统的关键字冲突.

标识符是区分大小写


端口列表


如以上的(oY,iA,iB,iC)就是端口列表

端口是模块和外界环境交换数据的接口,端口列表中必须出现本模块所具有的全部输入和输出端口,端口列表一般都是分为输入和输出两部分来书写,可以先写输入端口后写输出端口,也可以反过来。

端口列表用括号区分,括号内部写出所有的端口,每个端口的名称可以自己命名,属于标识符。

不同的端口之间以逗号隔开,仅列出名称,而不用体现该端口所具有的位宽。

当把 module关键字,模块名称、端口列表都写完后,需要在此行的末尾添加一个分号,作为本行结束的标志,模块的定义也就完成了。


端口声明


模块定义中的端口列表仅列出了本模块具有哪些端口,但这些端口是输人还是输出并没有定义,这就需要在模块中声明。

端口声明的作用就是声明端口的类型、宽度等信息

端口的类型有输人端口、输出端口和双向端口三种,关键字分别是input , output和 inout。

端口定义时默认l位宽度﹐即只能传播1位的有效信息,如果定义的端口中包含多位信息﹐需要指定端口的宽度,其语法结构如下:

端口类型 [端口宽度] 端口名;

举例:

input [31:0] iA;//声明一个32位input接口,分别为iA[31],iA[30],iA[29]…………iA[0];
output [31:0] oB;//声明一个32位output接口,分别位oB[31],oB[30],oB[29]…………oB[0];

端口声明中默认会把定义的端口声明为wire类型,即线网类型

对于端口的三种类型,除了output可能是寄存器类型(reg 类型)外, input与inout都必须是wire类型,线网类型和寄存器类型的区别在于:

  • 线网类型描述的电路形式是连线,线的一端有了数据立刻会传送到另外一端,一端的数据消失则另一端数据也消失,不能够保存数值;

  • 寄存器类型描述的电路形式是寄存器,可以保存某个数值直到下次更新。


门级调用


端口类型声明完后就是门级调用,语法格式如下:

逻辑门类型 <实例名称,可选>(端口连接);

//逻辑门类型就是常用的基本逻辑门

单输入逻辑门(buf缓冲器,not非门,[真值表如下])


举例:

点击查看代码
not n1(o,i);

//表示调用一个非门,名称叫做n1,输出信号o,输入信号i。

//在同一个模块中实例名称不要重复。逻辑门实例名称也可以不定义

即:

not (nS1,S1);

//此代码就是调用了一个非门,该非门的输入为S1,输出为nS1

/*
定义实例名称并不意味着该逻辑门没有名称,
而是Verilog HDL的内建语法会在编译过程中自动给这个逻辑门进行命名,
使得每个逻辑门都会有自己独有的实例名称。
*/

多输入逻辑门


多输入逻辑门中比较常见的有6种,分别是与门and与非门nand或门 or或非门nor ,异或门xor同或门xnor.

电路图:

真值表:


三态门


还有一类比较特殊的门,是带有控制信号的

包括bufif1 , bufifo , notiflnotifo,在原有的buf和not门上增加了一个控制信号,当控制信号生效时,输出有效数据,当控制信号不生效时,输出数据变为高阻态,所以也称为三态门.

电路图:

三态门功能表:

调用三态门语法如下:

三态门类型  实例名称  (输出信号,输入信号,控制信号);

如果一个模块中有多个同样的门,那么就可以定义'门数组'

例:

nand n[ 2:0](Y,A,B);

该行语句等同于下面3条语句:

nandn2( Y2,A2,B2) ;
nandn1( Y1,A1, B1);
nand DWn0 ( YO,A0, BO);

这种语法称为实例数组,在使用实例数组的时候,实例名称必须定义。


模块的实例化


前面介绍了一些基本逻辑门的调用,这些被调用的逻辑门也属于模块,只不过Verilog HDL的内建语法中已经定义好了,设计过程中直接享米使用即可。

verilog HDL的语法将模块内调用其他模块来完成设计的过程统称为悞块的实例化。

  • 我们可以类比C语言中的函数调用

基本语法格式如下:

模块名称  实例名称(接口列表)

模块名称即设计者已经定义好的其他模块的模块名(这也就意味着这里不能随意更改),实例名称是在本模块内定义的新名称(这个可以按照心情随意定义)。

端口连接是在当前模块中把实例化的模块所包含的端口进行连接,有两种连接方式:按顺序连接和按名称连接。


按顺序连接


module Test;
  reg a,b,c;//定义为reg是要连接实例化接口的输入端
  wire y;  //定义为wire是因为要连接实例化的输出端,调用的定义方式与定义的方式正好相反
           //即可以理解为reg接wire,wire接reg
   ……
  logic_gates mylogic_gates(y,a,b,c);
endmodule

//定义位置

module logic_gates(oY,iA,iB,iC);
  output oY;
  input  iA,iB,iC;
  ……
endmodule

按顺序连接要求连接到实例的信号必须与模块声明时目标端口在端口列表中的位置保持一致

另外,把实例化模块的输人端口所连接的信号定义为reg,把实例化模块的输出端口所连接的信号定义为wire,若实例化模块有双向端口,所连按的信号也要定义为wire,这是必须遵守的语法要求。

第一个模块是一个测试模块Test,在这个模块中调用了模块 logic_gates,实例化时重新命名为mylogic_gates

连接顺序按照下面logic_gates模块中定义的接口顺序依次连接。可以看出,连接的顺序与 logic_gates中的端口声明部分无关,仅考虑模块定义中的端口列表顺序


按名称连接


当模块的端口比较多的时候,端口的先后次序就容易混淆,按顺序连接方式就容易发生错误,此时就可以使用按名称连接的方式。按名称连接方式的端口连接语法如下:

.原模块中端口名称(新模块中连接信号名称)

我们把上面那种按顺序方式连接的方式修改为按名称连接的方式:

module Test;
  reg a,b,c;
  wire y;
  ……
  logic_gates mylogic_gates(.iA(a),.iB(b),.iC(c),.oY(y));
endmodule

如果在模块实例化的过程中,有些端口没有使用到,不需要进行连接,可以直接悬空。

对于按顺序连接方式,可以在不需要连接的端口位置直接留一个空格,以逗号来表示这个端口在原模块中的存在。

对于按名称连接方式,没有出现的端口名称就直接被认为是没有连接的端口。

两种端口连接方式在语法上都是可行的

通常按顺序连接只使用在门级建模和规模比较小的代码中,如简单的实验、课程的作业、自己编写研究的小段代码等。

按名称连接可叮以使用在所有的代码中,而且在实际设计中使用的端口名称都是具有实际意义的,使用按名称连接方式可以方便代码的调试,增加代码的可读性,所以在正式的设计代码中大都是使用按名称连接方式的。


内部连线声明


内部连线是在模块实例化过程中,在被实例化的各个模块之间连接输入和输出信号的数据连线,即前面提到的wire类型,其定义语法如下:

wire [线宽] 线名称;

在Verilog HDL代码的编译过程中,凡是在模块实例化中没有定义过的端口连接信号均被默认为1位的wire类型。

设计中都要把这些信号显式地声明出来﹐避免出现位宽不匹配的现象。

我们在最开始的地方加入连线声明

点击查看代码
module logic_gates(oY,iA,iB,iC);
  output oY; 
  input iA,iB,iC;
  wire and1,and2;   //连接线

  and(and1,iA,iB);
  and(and2,iA,iC);
  or(oY,and1,and2);
endmodule

层次化设计


自上而下的层次化设计流程

posted @ 2021-09-27 20:56  星空Dreamer  阅读(3795)  评论(0编辑  收藏  举报