Verilog HDL 学习笔记1data type

2013-05-02 18:13:20

  开始做毕设将近有两个月了,主要做的是《基于FPGA的基带解调器的设计》,其中最核心的部分是4096点FFT的设计。截止到目前,算是完成了4096点FFT的模块设计(仅仅modelsim仿真通过)。通过两个月的学习,对Verilog HDL有了新的认识。学习贵在总结,遂将心得体会记录!

Verilog HDL 学习笔记1-data type

  接触HDL时间其实挺长了,最开始接触的是VHDL,写过的最复杂的设计是一个自动量程的频率计。大三的ASIC课上接触到了Verilog HDL,从图书馆借了本书(书名具体叫啥忘了)准备好好学。看了该书一段时间(也就几天)后,发现Verilog 语法竟然这么复杂......直接扼杀了我对Verilog HDL的三分钟热度。后来才发现,我借的那本书是将verilog 1995标准直接翻译过来的,可综合语法和用来设计testbench等(水平有限,不太清楚不可综合的语法具体用来干啥)混在了一起。其实当时我想用到的只是可综合的部分,要是当时看的书能清楚地指明这点,估计也不会走这么多弯路了。可见,对于入门者而言,选对书很重要!后来在学长的推荐下,看了夏宇闻老师的《Verilog 数字系统设计教程》,感觉挺不错的!以下的学习笔记很大部分出自该书。

  絮絮叨叨这么多,现在要开始进入正题了!无论学习任何语言,第一步毫无疑问是学习语法。而学习verilog语法,第一个疑惑点就在于 Verilog HDL的data type。对于可综合的设计而言,疑惑就在于 wire 和 reg 的区别。

  闲话不多说,先上Verilog 2001(IEEE Standard Verilog Hardware Description Language)对于data type 的描述:

There are two main groups of data types: the variable data types and the net data types. These two groups differ in the way that they are assigned and hold values. They also represent different hardware structures.

  Net declarations:The net data types shall represent physical connections between structural entities, such as gates. A net shall not store a value (except for the trireg net). Instead, its value shall be determined by the values of its drivers, such as a continuous assignment or a gate. See Section 6 and 7. for definitions of these constructs. If no driver is connected to a net, its value shall be high-impedance (z) unless the net is a trireg, in which case it shall hold the previously driven value. It is illegal to redeclare a name already declared by a net, parameter,or variable declaration (see 3.12).

  Variable declarations:A variable is an abstraction of a data storage element. A variable shall store a value from one assignment to the next. An assignment statement in a procedure acts as a trigger that changes the value in the data storage element. The initialization value for reg, time, and integer data types shall be the unknown value, x. The default initialization value for real and realtime variable datatypes shall be 0.0. If a variable declaration assignment is used (see 6.2.1), the variable shall take this value as if the assignment occurred in a blocking assignment in an initial construct. It is illegal to redeclare a name already declared by a net, parameter, or variable declaration.

  从上面可以看出,数据类型主要分为两类:变量型和 net型。其中net型主要代表的是物理连接,没有驱动时,值为高阻(Z)。变量型可以作为数据存储单元的抽象,初始值为不定值(X)。

  而对于可综合代码而言,net型主要代表为wire,变量型主要代表为reg,下面继续贴Verilog 2001对于wire 和 reg的描述:

  Wire and tri nets:The wire and tri nets connect elements. The net types wire and tri shall be identical in their syntax and functions;two names are provided sothat the name of a net can indicate the purpose of the net in that model. A wire net can be used for nets that are driven by a single gate or continuous assignment. The tri net type can be used where multiple drivers drive a net.

  regs:Assignments to a reg are made by procedural assignments (see 6.2 and 9.2). Since the reg holds a value between assignments, it can be used to model hardware registers. Edge-sensitive (i.e., flip-flops) and level sensitive (i.e., RS and transparent latches) storage elements can be modeled. A reg needs not represent a
hardware storage element since it can also be used to represent combinatorial logic.

  从上面可以看到:wire是用来连接元素的,起物理连接作用。而最最值得主要的是:reg在两次赋值之间保存值,基于以上特性,reg可以建模硬件存储单元。注意!!仅仅是可以,不是一定!

看完了官方定义,再来听听别人对wire和reg的理解。首先看看夏宇闻老师书中对wire和reg的描述:

  wire :wire型数据常用来表示用以assign关键字指定的组合逻辑信号。Verilog程序模块中输入、输出信号类型默认时自从定义为wire型。wire型信号可以用做任何方程式的输入,也可以用做“assign”语句或实例元件的输出

  reg:寄存器是数据存储单元的抽象。寄存器数据类型的关键字是reg。通过赋值语句可以改变寄存器存储的值,其作用与改变触发器存储的值相当。....(此处省略不少字),reg型数据常用来表示“always”模块中的指定信号,常代表触发器。通常,在设计中要由“always”模块通过使用行为描述语句来表达逻辑关系。在“always”模块中内被赋值的每一个信号都必须定义成reg型。

  注意:(注意这个“注意”是夏宇闻老师书中的注意,不是我的“注意”,夏老师书中的“注意”通常非常具有指导性!)reg型只表示被定义的信号将用在“always”模块内,理解这一点很重要(我也觉得理解这一点很重要,所以加粗了)。并不是说reg型信号一定是寄存器或触发器的输出,虽然reg型信号常常是寄存器或触发器的输出,但并一定总是这样(嗯嗯,和“并不是所有的牛奶都是特仑苏”一个意思)。在本书中还会对这一点做更详细的解释(嗯嗯,我下面也会做解释的)。

  参考夏老师对于reg和wire的理解,可以得出如下结论:在assign中赋值的信号定义成“wire”,在always中赋值的信号定义成“reg”!“reg”不一定是寄存器或触发器的输出,也就是说用了reg不一定综合出来的是寄存器或者触发器或者transparent Latches(锁存器)。

  在看完了夏老师的精彩理解之后,再看看网友对其的理解。以下内容来自百度文库《verilog中wire与reg的区别》,其中黑色部分为文章原文,黄色部分为个人理解(至于为什么是黄色?嗯嗯,本人喜欢黄色)    

  verilog中reg和wire类型的区别和用法

   reg相当于存储单元,wire相当于物理连线

  夏老师已经说过了,reg不一定相当于存储单元

  

  Verilog 中变量的物理数据分为线型和寄存器型。这两种类型的变量在定义时要设置位宽,缺省为1位。变量的每一位可以是0,1,X,Z。其中x代表一个未被预置初始        状态的变量或者是由于由两个或多个驱动装置试图将之设定为不同的值而引起的冲突型线型变量。z代表高阻状态或浮空量。线型数据包括wire,wand,wor等几种类型在被一个以上激励源驱动时,不同的线型数据有各自决定其最终值的分辨办法。

  不能同意更多

  输入端口可以由net/reg驱动,但输入端口只能是net;输出端口可以使net/reg类型,输出端口只能驱动net;若输出端口在过程块中赋值则为reg型,若在过程块外赋值则为net型用关键词inout声明一个双向端口, inout端口不能声明为寄存器类型,只能是net类型。

  以后会细说inout的用法

  

  wire表示直通,即只要输入有变化,输出马上无条件地反映;reg表示一定要有触发,输出才会反映输入。

  不指定就默认为1位wire类型。专门指定出wire类型,可能是多位或为使程序易读。wire只能被assign连续赋值,reg只能在initial和always中赋值。wire使用在连续赋值语句中,而reg使用在过程赋值语句中。在连续赋值语句中,表达式右侧的计算结果可以立即更新表达式的左侧。在理解上,相当于一个逻辑之后直接连了一条线,这个逻辑对应于表达式的右侧,而这条线就对应于wire。在过程赋值语句中,表达式右侧的计算结果在某种条件的触发下放到一个变量当中,而这个变量可以声明成reg类型的。根据触发条件的不同,过程赋值语句可以建模不同的硬件结构:如果这个条件是时钟的上升沿或下降沿,那么这个硬件模型就是一个触发器;如果这个条件是某一信号的高电平或低电平,那么这个硬件模型就是一个锁存器;如果这个条件是赋值语句右侧任意操作数的变化,那么这个硬件模型就是一个组合逻辑。

  喜欢其后面对于“不一定”解释

 

简单来说硬件描述语言有两种用途:1、仿真,2、综合。

 

对于wire和reg,也要从这两个角度来考虑。

 

*********************************************************************************
从仿真的角度来说,HDL语言面对的是编译器(如Modelsim等),相当于软件思路。
这时:
wire对应于连续赋值,如assign
reg对应于过程赋值,如always,initial

 

*********************************************************************************
从综合的角度来说,HDL语言面对的是综合器(如DC等),要从电路的角度来考虑。
这时:
1、wire型的变量综合出来一般是一根导线;
2、reg变量在always块中有两种情况:
(1)、always后的敏感表中是(a or b or c)形式的,也就是不带时钟边沿的,综合出来还是组合逻辑
(2)、always后的敏感表中是(posedge clk)形式的,也就是带边沿的,综合出来一般是时序逻辑,会包含触发器(Flip-Flop)

 

在设计中,输入信号一般来说你是不知道上一级是寄存器输出还是组合逻辑输出,那么对于本级来说就是一根导线,也就是wire型。而输出信号则由你自己来决定是寄存器输出还是组合逻辑输出,wire型、reg型都可以。但一般的,整个设计的外部输出(即最顶层模块的输出),要求是寄存器输出,较稳定、扇出能力也较好。

 

   不能同意更多

 以下的部分也摘自该文章,貌似是一名爱刨根究底的老外对于wire和reg到底综合后生成啥玩意儿做的验证

  

  Well I had this doubt when I was learning Verilog: What is the difference between reg and wire? Well I won't tell stories to explain this, rather I will give you some

 examples to show the difference.(这哥们够实诚)

 

There is something else about wire which sometimes confuses. wire data types can be used for connecting the output port to the actual driver. Below is the code

 which when synthesized gives a AND gate as output, as we know a AND gate can drive a load.

module wire_example( a, b, y);   
input a, b;   
output y;   

wire a, b, y;   
assign y = a & b;   

endmodule 
module wire_example( a, b, y);
input a, b;
output y;

wire a, b, y;
assign y = a & b;

endmodule

SYNTHESIS OUTPUT

What this implies is that wire is used for designing combinational logic, as we all know that this kind of logic can not store a value. As you can see from the example

 above, a wire can be assigned a value by an assign statement. Default data type is wire: this means that if you declare a variable without specifying reg or wire, it will 

be a 1-bit wide wire.

 Now, coming to reg data type, reg can store value and drive strength. Something that we need to know about reg is that it can be used for modeling both combinational 

and sequential logic. Reg data type can be driven from initial and always block.

Reg data type as Combinational element

module reg_combo_example( a, b, y);   
input a, b;   
output y;   
      
reg   y;   
wire a, b;   
      
always @ ( a or b)   
begin    
     y = a & b;   
end   
     
endmodule 
module reg_combo_example( a, b, y);
input a, b;
output y;
   
reg   y;
wire a, b;
   
always @ ( a or b)
begin 
     y = a & b;
end

endmodule

SYNTHESIS OUTPUT

 

This gives the same output as that of the assign statement, with the only difference that y is declared as reg. There are distinct advantages to have reg modeled as

 combinational element; reg type is useful when a "case" statement is required (refer to the Verilog section for more on this).

    To model a sequential element using reg, we need to have edge sensitive variables in the sensitivity list of the always block.

 

Reg data type as Sequential element


module reg_seq_example( clk, reset, d, q);
input clk, reset, d;
output q;
    
reg   q;
wire clk, reset, d;

always @ (posedge clk or posedge reset)
if (reset) begin
    q <= 1'b0;
end else begin
    q <= d;
end

endmodule

SYNTHESIS OUTPUT

 

There is a difference in the way we assign to reg when modeling combinational logic: in this logic we use blocking assignments while modeling sequential logic we

 use nonblocking ones.


    From the college days we know that wire is something which connects two points, and thus does not have any driving strength. In the figure below, in_wire is 

a wire which connects the AND gate input to the driving source, clk_wire connects the clock to the flip-flop input, d_wire connects the AND gate output to the flip-flop D input

 

终于要到了综上所述的时候了!!

综上所述,关于如何选用wirereg,可总结出以下几条指导性原则:

1. assign 中赋值的信号定义为wire,在always块中赋值的信号定义为reginout型信号定义为wire

2. 输入端口可以由net/reg驱动,但输入端口只能是net;输出端口可以使net/reg类型,输出端口只能驱动net;若输出端口在过程块中赋值则为reg型,若在过程块外赋值则为net型用关键词inout声明一个双向端口, inout端口不能声明为寄存器类型,只能是net类型。

3. 关于综合出来的结果:wire综合出来是物理连线,reg型具体综合成register,还是flip-flop,还是latch,还是普通组合逻辑输出由代码决定。但可以肯定的是,对reg型的赋值一定出现在always块内。(千万不要觉得reg综合出来的就是register的输出,不要因为名字相似就把两者绑在一起!人家国产乔丹意思是南方之乔木呢,和外国某篮球运动员“Jordan”没有半毛钱关系呢,虽然他的商标出卖了他的解释)

4. 在创建顶层模块或者调用(实例化)其他模块时,起纯连接作用的信号定义为wire(貌似重复了,但是由于犯过几次错,特地提出来)

以上乃个人学习总结,不足之处请拍砖!

 

原文地址:https://www.cnblogs.com/LNAmp/p/3055945.html