Verilog HDL三种基本描述方式-结构化描述

当我们使用Verilog HDL代码来描述硬件功能的时候,可采用三种不同方式或混合方式对设计进行建模,这些方式包括:结构化方式—使用门和模块实例语句描述建模;数据流方式—使用连续赋值语句方式建模;行为描述方式—使用过程化结构建模。

1. 结构化方式

在这里插入图片描述

1.1门级结构建模(内置门原语)

Verilog HDL 中有关门类型的关键字共有26个,下面列举了8个基本的门类型(gatetype)关键字和它们所代表门的类型:

and——与门;
nand——与非门;
nor——或非门;
or——或非门;
xor——异或门;
xnor——异或非门;
buf——缓冲器;
not——非门;

门与开关的说明语法可以用标准的声明语句格式和一个简单的实例引用加以说明。

门声明语句格式如下:

<门的类型> [<驱动能力><延时>] <门实例1>[,<门实例2>,……,<门实例n>];

nand #10 nd1(a,data,clock,clear);

门的类型是门声明语句所必须的,它可以是Verilog HDL 语法规定的26种门类型中的任意一种。上述该例说明在模块中声明了nand与非门语句。

驱动能力和延时是可选项,可根据不同的情况选不同的值或不选。上述该例中#10说明输出与输入延时了10个单位时间。

<门实例1>是在本模块中引用的第一个这种类型的门,而<门实例n>是引用的第n个这种类型的门。上述该例在模块中使用了一个名为nd1的与非门,输入为data,clock和clear,输出为a。(在声明门实例时可能编译会报错。)

 逻辑图:

在这里插入图片描述

 模块代码示例(1位全加器对应上述逻辑图):

module FA_Str(A,B,Cin,Sum,Cout);

input A,B,Cin;
output Sum,Cout;

/*门实例由线网类型变量S1,T1,T2和T3互连*/
wire S1,T1,T2,T3;

/*由于没有指定顺序,门实例语句可以以任何顺序出现*/
/*X1,X2,A1等都是实例名称,紧跟在每个门后的信号列表是它的互连*/
/*列表中的第一个是门的输出,余下的是输入*/
	xor 
			X1(S1,A,B),				//注意结束时用逗号,最后才用分号
			X2(Sum,S1,Cin);      //表示X1和X2都是xor异或门
	 
	 
	and 
			A1(T3,A,B),
			A2(T2,B,Cin),
			A3(T1,A,Cin);

	or
		 O1(Count,T1,T2,T3);

endmodule

在这个结构描述的模块中,FA_Str定义了模块名,设计上层模块时可以用模块名(FA_Str)调用这个模块。

 由已经设计成的模块构成更高一层的模块

如果已经编制了一个模块,如上例中的FA_Str,可以在另外的模块中引用这个模块,引用的方法与门类型的实例引用非常类似,只须在前面写上已编的模块名,紧跟着写上引用的实例名,按顺序写上实例的端口名即可,也可以用已编模块的端口名按对应原则逐一填入,详见以下两种语句:(注意在FA_Str1实例中端口已经申明,只须将对应信号的连接点注明)

(1)FA_Str FA_Str1(FA[1],FB[1],FTemp[1],FSum[1],FCount[1]);

(2)FA_Str FA_Str1(.B(FB[1]),.A(FA[1]),.Cin(FCin),.Sum(FSum[1]),.Count(FTemp[2]))

这两条语句都表示实例FA_Str1引用已编模块FA_Str,也可以将FA_Str实例化了FA_Str1。从上面两条语句可以看出在引用实例时,FA_Str1的端口信号与FA_Str的端口对应有两种不同的表示方法,即模块实例化的端口名可以有序排列,也可以不必按序排列,如果模块的端口名按序排列,只须按序列出实例的端口名(见语句1),如果不按序排列,则实例的端口信号和被引用模块的端口信号必须一一列出。(见语句2)

 逻辑图

在这里插入图片描述

 模块代码实例(4位全加器对应上面逻辑图)

/*四位全加器使用4个1位全加器模块描述*/

module FourBitFA(FA,FB,FCin,FSum,FCout);

parameter SIZE = 4;

input [SIZE:1] FA,FB;
output [SIZE:1] FSum;
input FCin;
input FCout;

wire [1:SIZE-1] FTemp;

/*在模块实例语句中,端口可以与名称或位置关联*/

FA_Str

/*FA1和FA2使用命名关联方式,也就是说端口的名称和它
连接的线网被显示描述(每一个的形式都为“.port_name(net_name)”)*/

/*如果不需要FA_Str端口的的某个端口,可以在FA1和FA2端口中省去,
即可以在FA1和FA2中不出现某端口*/

FA1(.A(FA[1]),.B(FB[1]),.Cin(FCin),.Sum(FSum[1]),.Cout(FTemp[2])),
FA2(.A(FA[2]),.B(FB[2]),.Cin(FTemp[1]),.Sum(FSum[2]),.Cout(FTemp[2])),

/*FA3和FA4使用位置关联方式将端口与线网关联,这里的关联顺序很重要,
必须一一对应,例如在实例FA4中,第一个FA[4]与FA_Str的端口A连接,
第二个FB[4]与FA_Str的端口B连接,余下的一一对应,由此类推。*/

/*如果不需要FA_Str端口的的某个端口,可以在FA3和FA4端口中省去,但逗号依然保留。
如,FA3(FA[3],FB[3],,FSum[3],FTemp[3])*/

FA3(FA[3],FB[3],FTemp[2],FSum[3],FTemp[3]),
FA4(FA[4],FB[4],FTemp[3],FSum[4],FCout);

endmodule

显而易见,通过模块实例引用,可以构成任何复杂结构的电路。这种以结构方式所建立的Verilog模型不仅可以仿真,也是可以综合的,其本质表示电路的具体结构,也就是说,这种Verilog文件也是一种结构网表。

1.2开关级结构建模

通过调用Verilog HDL内部的基本开关元件来对硬件电路的结构进行说明,这种情况下的模块由基本的开关级元件实例组成,这种抽象程度更低,基本不用掌握。

nmos 实例名(out,data,ctrl);
pmos 实例名(out,data,ctrl);
supply1 vdd;源极(逻辑1)
supply0 vdd;地级(逻辑0);

1.3用户定义的原语(UDP)

and,or,not等逻辑门是Verilog HDL 自带的内建语法,对这些门的描述是以原语的形式在Verilog HDL中定义的,即内置原语。

在实际设计中,有时会需要使用自己编写的原语,这种原语就是用户自定义原语(User Defined Primitive ,UDP),也就是说可以利用UDP来定义自己用于仿真的基本逻辑元件模块并建立相应的原语库,这样就可以与调用Verilog HDL基本逻辑元件一样的方法来调用原语库中的相应元件模块,并进行仿真。

与一般的用户模块相比,UDP更为基本,它只能简单描述简单的能用真值表表示的组合或时序逻辑。UDP模块结构与一般模块类似,只是不用module而改用primitive关键词开始,以endprimitive关键词结束。

 定义UDP语法

primitive 元件名(输出端口名,输入端口名1,输入端口名2……)
output 输出端口名;
input 输入端口名1,输入端口名2,……;

reg 输出端口名;
initial begin
     输出端口寄存器或时序逻辑内部寄存器赋初值(0,1或X);
end
//这两行在时序UDP中使用
table
//输入1   输入2   输入3   ……   :   输出
 逻辑值   逻辑值   逻辑值   ……   :  逻辑值;
逻辑值   逻辑值   逻辑值   ……   :  逻辑值;
逻辑值   逻辑值   逻辑值   ……   :  逻辑值;
……      ……     ……    ……   :   ……;
endtable
endprimitive

 注意点

(1) UDP只能有一个输出端,而且必定是端口说明列表的第一项。

Output a,b;//多个输出违法

(2) UDP可以有多个输入端,最多允许有10个输入端。

Input d3,d2,d2,d0;//合法

(3) UDP所有端口变量必须是标量,也就是必须是1位的。

Output [1:0] c;//多位输出违法
Input [3:0] d;//多位输入违法

(4) 时序电路的UDP需要保存状态,所以时序电路UDP的输出端口要声明为reg类型,且只有输出端才可以被定义成reg型变量。

(5) Initial语句用于为时序电路内部寄存器赋初值,该语句可选,且只允许赋0,1,X3种逻辑值,默认值为X。

(6) UDP与module同级别,所以模块内部不能定义UDP,但可以在模块内调用已定义的UDP,语法与门级调用完全相同。

(7) UDP的真值表项可以处理0,1,X值,不能处理Z值,本身UDP不能输出Z值,输入给UDP的Z值会被当做X值来处理。

(8) UDP中不能使用inout端口。

 二输入与非门(UDP)

primitive nand_udp(Y,A,B);


output Y;
input A,B;

table

/*输入信号1   输入信号2  :  输出信号;*/
	/*A B : Y,输入信号的顺序一定和UDP端口列表中的输入信号顺序相同*/
	  0 0 : 1;
	  0 1 : 1;
	  1 0 : 1;   //输入和输出之间以“:”分开隔开,每一行结束处以“;”结束。
	  1 1 : 0;
/*状态表中要包含所有确定输出的输入情况,即做到	 每种可以得到确定
输出值的输入都有对应的列表行与之相对应。*/ 
endtable

endprimitive

Top-down流程

在这里插入图片描述

发布了16 篇原创文章 · 获赞 16 · 访问量 1339

猜你喜欢

转载自blog.csdn.net/sinat_41653350/article/details/104016003
今日推荐