Verilog的数据流、行为、结构化与RTL级描述
Verilog语言可以有多种方式来描述硬件,同时,使用这些描述方式,又可以在多个抽象层次上设计硬件,这是Verilog语言的重要特征。
在Verilog语言中,有以下3种最基本的描述方式:
-
- 数据流描述:采用assign连续赋值语句
- 行为描述:使用always语句或initial语句块中的过程赋值语句(推荐掌握)
- 结构化描述:实例化已有的功能模块或原语
以一个4位全加器为例:
module Full_Add_4b_1( A, B, Cin, Sum, Cout ); input[3:0] A; input[3:0] B; input Cin; output[3:0] Sum; output Cout; assign {Cout, Sum} = A + B + Cin; endmodule |
module Full_Add_4b_2( A, B, Cin, Sum, Cout ); input[3:0] A; input[3:0] B; input Cin; output[3:0] Sum; output Cout; reg [3:0] Sum; reg Cout; always @(A or B or Cin) begin {Cout, Sum} <= A + B + Cin; end endmodule |
`include "Full_Add_4b_1.v" module Full_Add_4b_3( A, B, Cin, Sum, Cout ); input[3:0] A; input[3:0] B; input Cin; output[3:0] Sum; output Cout; //实例化全加器 Full_Add_4b_1 FA0( A, B, Cin, Sum, Cout ); endmodule |
下面逐一对这些描述方式进行介绍:
数据流描述
在数字电路中,信号经过组合逻辑时会类似于数据流动,即信号从输入流向输出,并不会在其中存储。当输入发生变化时,总会在一定时间以后体现在输出端。同样,我们可以模拟数字电路的这一特性,对其进行建模,这种建模方式通常被称为数据流建模。数据流描述中最基本的语句是assign连续赋值语句。
图中的模型可以用如下语句来描述:
asssign #1 A_xor_wire = eq0 ^ eq1;
在任意一个时刻,A_xor_wire线网的值都是由eq0和eq1决定的,也可以说是由它们驱动的。
下面对连续赋值语句的特点进行说明:
一、连续驱动
连续赋值语句是连续驱动的,也就是说只要输入发生变化,都会导致该语句的重新计算。
二、只有线网类型的变量才能在assign语句中被赋值
由于连续赋值语句中被赋值的变量在仿真器中不会存储其值,因此该变量是线网类型(Net)的,而不是寄存器类型的。
另外,线网类型的变量可以被多重驱动,也就是说可以在多个连续赋值语句中驱动同一个线网。
但是寄存器变量就不同了,它不能被不同的行为进程(例如always语句块)驱动。
三、使用assign对组合逻辑建模
建议使用assign对组合逻辑建模,这是因为assign语句的连续驱动特点与组合逻辑的行为非常相似,而且在assign语句中加延时可以非常精确地模拟组合逻辑的惯性延时。
四、并行性
assign语句与行为语句块(always和initial)、其它连续赋值语句、门级模型之间是并行的。一个连续赋值语句是一个独立的进程,进程之间是并发的,同时也是交织的。
五、实例
这是一个半加器,使用连续赋值语句描述这个电路。
module Half_Add( X, Y, Sum, C_out ); //半加器 input X; input Y; output Sum; output C_out; assign Sum = X ^ Y, C_out = X & Y; endmodule |
|
行为描述
行为方式的建模是指采用对信号行为级的描述(不是结构级的描述)的方法来建模。在表示方面,类似数据流的建模方式,但一般是把用initial 块语句或always 块语句描述的归为行为建模方式。行为建模方式通常需要借助一些行为级的运算符如加法运算符(+),减法运算符(-)等。
例: 一位全加器的行为建模
module Full_Add_1b_2( A, B, Cin, Sum, Cout );
input A;
input B;
input Cin;
output Sum;
output Cout;
reg Sum;
reg Cout;
always @(A or B or Cin)
begin {Cout, Sum} <= A + B + Cin;
end endmodule
需要先建立以下概念:
1、只有寄存器类型的信号才可以在always和initial 语句中进行赋值,类型定义通过reg语句实现。
2、always 语句是一直重复执行,由敏感表(always 语句括号内的变量)中的变量触发。
3、always 语句从0 时刻开始。
4、在begin 和end 之间的语句是顺序执行,属于串行语句。
结构化描述
结构化描述就是说在设计中实例化已有的功能模块,这些功能模块包括门原语、用户自定义原语(UDP)和其他模块(module)。以下是结构化描述的3种实例类型:
-
- 实例化其他模块
- 实例化门(如与门and、异或门xor等)
- 实例化UDP
结构化的描述方式反映了一个设计的层次结构。
例[1]:一位全加器
module Full_Add_1b_3( A, B, Cin, Sum, Cout ); input A; input B; input Cin; output Sum; output Cout; wire S1, T1, T2, T3; // -- statements -- // xor x1 (S1, A, B); xor x2 (Sum, S1, Cin); and A1 (T3, A, B ); and A2 (T2, B, Cin); and A3 (T1, A, Cin); or O1 (Cout, T1, T2, T3 ); endmodule |
该实例显示了一个全加器由两个异或门、三个与门、一个或门构成。S1、T1、T2、T3则是门与门之间的连线。代码显示了用纯结构的建模方式,其中xor 、and、or 是Verilog HDL 内置的门器件。
以 xor x1 (S1, A, B) 该例化语句为例:
xor 表明调用一个内置的异或门,器件名称xor ,代码实例化名x1(类似原理图输入方式)。括号内的S1,A,B 表明该器件管脚的实际连接线(信号)的名称 ,其中 A、B是输入,S1是输出。其他同。
例[2]:两位全加器
两位的全加器可通过调用两个一位的全加器来实现。该设计的结构图如下:
`include "Full_Add_1b_3.v" module Full_Add_2b_3( FA, FB, FCin, FSum, FCout ) ; parameter SIZE = 2; input [SIZE:1] FA; input [SIZE:1] FB; input FCin; output [SIZE:1] FSum; output FCout; wire FTemp; Full_Add_1b_3 FA1( .A (FA[1]), .B (FB[1]), .Cin (FCin) , .Sum (FSum[1]), .Cout (FTemp) ); Full_Add_1b_3 FA2( .A (FA[2]), .B (FB[2]), .Cin (FTemp) , .Sum (FSum[2]), .Cout (FCout) ); endmodule
该实例用结构化建模方式进行一个两位的全加器的设计,顶层模块Full_Add_2b_3 调用了两个一位的全加器 Full_Add_1b_3。在这里,以前的设计模块Full_Add_1b_3 对顶层而言是一个现成的器件,顶层模块只要进行例化就可以了。
注意这里的例化中,端口映射(管脚的连线)采用名字关联,如 .A (FA[2]) ,其中.A 表示调用器件的管脚A,括号中的信号表示接到该管脚A的电路中的具体信号。 wire 保留字表明信号FTemp 是属线网类型。
另外,在设计中,尽量考虑参数化的问题
RTL级,register transfer level,指的是用寄存器这一级别的描述方式来描述电路的数据流方式;而Behavior级指的是仅仅描述电路的功能而可以采用任何verilog语法的描述方式。鉴于这个区别,RTL级描述的目标就是可综合,而行为级描述的目标就是实现特定的功能而没有可综合的限制。
行为级是RTL的上一层,行为级是最符合人类逻辑思维方式的描述角度,一般基于算法,用C/C++来描述。从行为级到RTL级的转换,一般都是由IC设计人员手工翻译。
这个过程繁琐,工作量很大,特别是随着数字系统的复杂性提升,这样的纯手工"翻译"过程容易出错,且使得开发周期变长。一批高级综合工具应运而生。如Menter Graphics的高层次综合工具Catapult C Synthesis。能够将数字系统的行为级描述映射为RTL设计,并满足给定的目标限制。从层次由上到下,数字系统的设计过程为:
Idea->行为级描述->rtl描述->门级网标->物理版图
行为级的描述更多的是采取直接赋值的形式,只能看出结果,看不出数据流的实际处理过程。其中又大量采用算术运算,延迟等一些无法综合的语句。常常只用于验证仿真。
RTL级的描述就会更详细一些,并且从寄存器的角度,把数据的处理过程表达出来。可以容易地被综合工具综合成电路的形式。
行为级描述可是说是RTL的上层描述,比RTL更抽象。行为描述不关心电路的具体结构,只关注算法。
有行为综合工具,可以直接将行为级的描述综合为RTL级的,比如Behavioral Compiler。
在硬件设计中有一句著名的话:thinking of hardware。RTL在很大程度上是对流水线原理图的描述。哪里是组合逻辑,哪里是寄存器,设计者应该了然于胸。组合逻辑到底如何实现,取决于综合器和限制条件。
rtl级可以理解为,可以直接给综合工具生成你要的网表的代码,而行为级则不行。比如real可以用于行为级,而不能用于rtl级!
行为级 is for testbench for modelling.
RTL is for synthesis
语法块如果可以被综合到gate level,就是RTL的。否则就是behavior level的。
同样是for语句,如果循环条件是常数,就是RTL的,如果是变量,就是behavior的。
行为级不考虑电路的实现,不考虑综合
RTL级描述数据在寄存器层次的流动模型。
always 属于行为级模型,是最基本的行为模型,是可以综合的。
综合与RTL或者行为级没有必然联系,虽然大多数行为模型不能综合
从网上copy
目的区别:
行为级描述目的是加快仿真速度,做法是尽量减少一个always块中要执行的语句数量,其结果不是为了综合,只关注算法。有行为综合工具,可以直接将行为级的描述综合为RTL级的,比如Behavioral Compiler。
形式区别:
RTL级描述是为了综合工具能够正确的识别而编写的代码,verilog中有一个可综合的子集,不同的综合工具支持的也有所不同, RTL级的描述就会更详细一些,并且从寄存器的角度,把数据的处理过程表达出来。可以容易地被综合工具综合成电路的形式。可以采用任何verilog语法 的描述方式。鉴于这个区别,RTL级描述的目标就是可综合,
行为级的描述更多的是采取直接赋值的形式,只能看出结果,看不出数据流的实际处理过程。其中又大量采用算术运算,延迟等一些无法综合的语句。常常只用于验证仿真。
电路区别:
RTL级,register transfer level,指的是用寄存器这一级别的描述方式来描述电路的数据流方式;RTL在很大程度上是对流水线原理图的描述。哪里是组合逻辑,哪里是寄存器,设计 者应该了然于胸。组合逻辑到底如何实现,取决于综合器和限制条件。 RTL是晶体管传输级,描述硬件的相互联接关系,一般都可以综合;
而Behavior级指的是仅仅描述电路的功能而在硬件设计中有一句著名的话:thinking of hardware。简单说,rtl就是用寄存器和组合逻辑组成,不能再用其他construct;behavior就是指定输入和输出之间的关系。
混乱点: 有时感觉RTL级是行为级与数据流级的混合应用。
乐点: 同样是for语句,如果循环条件是常数,就是RTL的,如果是变量,就是behavior的。
转:https://blog.csdn.net/a8039974/article/details/43635257