Menu Close

Verilog always过程

上节内容从总体上讲解了顺序语句的特点,always过程,函数 function,任务task等在循序语句描述中又各有特点,本节内容以always过程为主进行详细讲解。

  1. always顺序语句结构

由always 引导的顺序语句,又称为always 过程语句。一般由begin…end包起来的一条或多条语句组成的。多条语句之间是按顺序执行的。

其定义的格式如下:


由关键字always@引导,后跟括号(…)用来描述always块启动,所需激励的变量。例如:


其中a , b , c是always块内需要使用的变量,当括号()内的变量任何一个发生变化,always内的过程语句就会执行一次。因此这些变量又称为敏感量。由这些敏感量组成了always需要的所有变化检测量表,称为敏感表。如:(a,b)就是敏感表。只要敏感表中任何一个变量的值有变化,always过程就会启动。

always块是由begin…end隔离的,当只有一条语句时,begin和end也可以省略。如:



在Verilog 2001的语法中,也允许不指定敏感量,由编译系统根据always过程使用的变量自动推断。如:

2. always 过程内语句的特点

  • always过程内的语句只能对reg型变量赋值

always过程内的语句只能对reg型变量赋值,不能对wire变量赋值,也不能使用assign赋值语句。上节内容已经介绍,过程之间不能相互嵌套。

  • always过程内的语句是顺序执行的

always 过程内的语句是顺序执行,因此对过程内的语句书写顺序是有要求的。见上节内容“Verilog顺序语句”

3. assign 与 always 比较。

  • 对敏感量的处理

assign 是连续赋值语句,对赋值语句右边表达式的变量实时监测,一旦变量的值变化即评估表达式的值,并进行赋值。而always是对敏感表中的敏感量实时监测,一旦敏感量的值发生变化,即启动always过程。从这一点上看,二者是一致的,可以认为assign 赋值语句就是缩小版的always过程。但对于非阻塞赋值语句,always@(*)的敏感表也包含被赋值变量,因此可以引起always过程的重入。

例:


上例中,除了在assign赋值语句中要求c是wire 型变量,always要求reg 型变量外,其结果可以认为是相同的。

 

  • always过程可以处理更复杂的过程

    1. always过程内允许同一个变量多次赋值,而且语句执行具有顺序性。
    2. 有更复杂的判断即分支语句可以在always过程中使用,如if …else if …else(见分支选择语句),case… endcase(见分支选择语句),?语句等。而assign 赋值语句只能使用较简单的问号(?)语句(见分支选择语句)。
    3. always过程内可以同时处理多个if、case块 ,if, case 等可以相互嵌套。可给多个变量赋值,同一个变量可以多次赋值。
    4. always过程支持时钟边沿激励(如 posedge 与negedge),assign赋值语句不支持边沿检测激励。

例 1: 十进制加1计数器


 

Verilog 2001版本中的语法允许在 module端口中直接定义寄存器型输出端口,因此也可以改成下面的写法。


 

4.always过程语句中register的模型

  • 组合逻辑模型

由简单的赋值语句组成always过程是组合逻辑过程,此时reg类型起到的作用与wire类型变量类似。如: always@(*) c=a&b;

例2:3-8译码器:


 

例2中虽然在always过程中使用case语句,但依然是组合逻辑。

正逻辑的3/8译码器的程序如下:


 

  • 锁存器模型

由于在顺序语句的 reg类型数据,在条件满足时更新数据,在条件撤销后具有保持原数据的能力,因此很容易描述锁存器。锁存器的用途非常广泛,著名的单片机芯片MCS8051的P0口就是利用锁存器实现地址/数据复用。

例3:锁存器(Latch)


 

上面的程序描述的功能是,在ALE为高电平时,addr(地址)随P0变化而改变,在ALE的下降沿时,将P0的值锁存在地址线(addr)上。在ALE为低电平时,数据(data)随P0的值而改变,在ALE的上升沿前通过读信号的上升沿将数据捕获,这是FPGA与单片机8051或早期Intel CPU 8088的接口设计。

  • 触发器模型

在时钟边沿的驱动下,寄存器的模型一般都等效为触发器,可建模为D边沿触发器,JK边沿触发器等。由于D 触发器的模型较为简单,因此一般都是以D边沿触发器作为参考模型。如:例1就可以以D触发器作为参考模型进行分析。

5. always 时钟模型

在always模型中还有一种简单的模型,该模型不需要敏感表,多由于生成仿真用的时钟。如:

          always   #5 clk=~clk;

由于该过程没有敏感量,默认为不需要敏感量的变化激励就可以运行,因此一定要有延迟语句保证不会陷入0延迟的死循环中,这一点与forever的行为相似。

          如 always clk=~clk; 该语句是错误的,要么编译语法错误,要么引起仿真死循环,仿真不出任何波形等一系列难以理解的现象。当然正确使用该语句,还需要将变量正确初始化。

真确写法如下:

 


由于在综合时会自动忽略延迟,因此”always  #5 clk=~clk;“语句,一定是不可综合的语句。

 

 

更多的模型建模内容请参照后续文章“阻塞与非阻塞赋值语句”的相关文章.

对应视频:

Posted in FPGA, FPGA 教材教案, Verilog