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
4位全加器.jpg
 




  下面逐一对这些描述方式进行介绍:

 

  数据流描述

  在数字电路中,信号经过组合逻辑时会类似于数据流动,即信号从输入流向输出,并不会在其中存储。当输入发生变化时,总会在一定时间以后体现在输出端。同样,我们可以模拟数字电路的这一特性,对其进行建模,这种建模方式通常被称为数据流建模。数据流描述中最基本的语句是assign连续赋值语句。

一个电路模型.jpg

 

  图中的模型可以用如下语句来描述:

  asssign #1 A_xor_wire = eq0 ^ eq1;

  在任意一个时刻,A_xor_wire线网的值都是由eq0和eq1决定的,也可以说是由它们驱动的。


  下面对连续赋值语句的特点进行说明:

  一、连续驱动

  连续赋值语句是连续驱动的,也就是说只要输入发生变化,都会导致该语句的重新计算。

  二、只有线网类型的变量才能在assign语句中被赋值

  由于连续赋值语句中被赋值的变量在仿真器中不会存储其值,因此该变量是线网类型(Net)的,而不是寄存器类型的。

  另外,线网类型的变量可以被多重驱动,也就是说可以在多个连续赋值语句中驱动同一个线网。

  但是寄存器变量就不同了,它不能被不同的行为进程(例如always语句块)驱动。

  三、使用assign对组合逻辑建模

  建议使用assign对组合逻辑建模,这是因为assign语句的连续驱动特点与组合逻辑的行为非常相似,而且在assign语句中加延时可以非常精确地模拟组合逻辑的惯性延时。

  四、并行性

  assign语句与行为语句块(always和initial)、其它连续赋值语句、门级模型之间是并行的。一个连续赋值语句是一个独立的进程,进程之间是并发的,同时也是交织的。

  五、实例

  这是一个半加器,使用连续赋值语句描述这个电路

 

HDL代码
RTL电路
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
一个电路模型.jpg
在Half_Add模块中,两个assign语句之间是独立并行的,它们的顺序与逻辑功能无关。

 


  行为描述

  行为方式的建模是指采用对信号行为级的描述(不是结构级的描述)的方法来建模。在表示方面,类似数据流的建模方式,但一般是把用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]:一位全加器

 

HDL代码
RTL电路
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
1位全加器.jpg

 

  该实例显示了一个全加器由两个异或门、三个与门、一个或门构成。S1、T1、T2、T3则是门与门之间的连线。代码显示了用纯结构的建模方式,其中xor 、and、or 是Verilog HDL 内置的门器件。

  以 xor x1 (S1, A, B) 该例化语句为例:

  xor 表明调用一个内置的异或门,器件名称xor ,代码实例化名x1(类似原理图输入方式)。括号内的S1,A,B 表明该器件管脚的实际连接线(信号)的名称 ,其中 A、B是输入,S1是输出。其他同。


  例[2]:两位全加器

  两位的全加器可通过调用两个一位的全加器来实现。该设计的结构图如下:

  

1位全加器设计结构图.jpg

 

 

`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

posted @ 2018-06-06 10:36  Luluuu  阅读(6639)  评论(0编辑  收藏  举报