Verilog HDL 学习笔记2-blocking and non-blocking assignment

来源:互联网 发布:coreidraw是什么软件 编辑:程序博客网 时间:2024/05/18 07:56

2013年5月6日 10:42:38

Verilog HDL 学习笔记2-blocking and non-blocking assignment

---学习贵在总结,将学习的心得体会记录

  在学习verilog的过程中,碰到的第一块绊脚石就是data type中wire 和reg的使用,第二块就是blocking 和non-blocking assignment 的区别和使用。现将学习过程中的疑惑和自己的理解总结。

  照惯例,还是先将官方说明贴出来,verilog 2001关于blocking and non-blocking assignment 表述如下:

blocking assignment :A blocking procedural assignment statement shall be executed before the execution of the statements that follow it in a sequential block (see 9.8.1). A blocking procedural assignment statement shall not prevent the execution of statements that follow it in a parallel block (see 9.8.2).

这表明的是:在顺序块中(begin end)中,阻塞过程赋值语句会阻塞其后语句的执行。也就是说,在前面的语句执行完之前,后面的语句是不能被执行的。但是在并行块中不会阻塞(fork join 语句,一般用不到)

non-blocking  assignment :The non blocking procedural assignment allows assignment scheduling without blocking the procedural flow. The non blocking procedural assignment statement can be used whenever several variable assignments within the same time step can be made without regard to order or dependence upon each other.

这表明的是:non-blocking assignment 不会阻塞过程块中的顺序语句,从用户的角度来看,这些语句是并行的。  

  官方的讲述总是不够细致,或者不够通俗易懂。那就来看看夏老师关于阻塞和非阻塞的理解,夏老师书中第14章《深入理解阻塞和非阻塞赋值的不同》详细介绍了区别和使用。

在该章概述中夏老师就提到了该章是根据国外的一篇论文,经过自己的理解编写而成的。虽然夏老师没有在参考文献中提到该篇论文,但是难逃google搜索啊,该论文是一位大牛之作,值得拜读。论文名为《Nonblocking Assignments in Verilog Synthesis, Coding Styles That Kill!》作者Clifford E. Cummings。

  首先来说的是在编写verilog代码时必须牢记的8个要点,才能在综合布局布线后的仿真中避免出现冒险竞争现象,原则如下:

  (1) 时序电路建模时,用非阻塞赋值

  (2)锁存器电路建模时,用非阻塞赋值

  (3)用always块建立组合逻辑模型时,用阻塞赋值

  (4)在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值

  (5)在同一个always块中不要即用非阻塞赋值又用阻塞赋值

  (6)不要在一个以上的always块中为同一个变量赋值

  (7)用$strobe系统任务来显示用非阻塞赋值的变量值

  (8)在赋值时不要使用#0延迟

 

其实从blocking 和 non-blocking 字面意思上来说,区别就是“阻塞”。要理解“阻塞”,还得从The Verilog "stratified event queue"说起,上述paper中对于"stratified event queue"的解释如下:

  An examination of the Verilog "stratified event queue" (see Figure 1) helps to explain how Verilog blocking and nonblocking assignments function. The "stratified event queue" is a fancy name for the different Verilog event queues that are used to schedule simulation events.

仿真器在仿真时将每个time step分成四个不同的队列,如下图所示:

每个公司的仿真器对于一个time step的处理安排可能不一样,下图来自某知名专家的讲稿:

 

对比两图可以看出:

对于阻塞和非阻塞赋值语句,均可以拆成两步,即evaluate(求值,求LHS的值) 和assign或update(赋值,将LHS值赋给RHS)。对于blocking assignment而言,evaluate和assign或update都在一个time step的开始时完成,只有在上一个blocking assignment statement完成后,同一个过程块中的下一个blocking assignment statement才能开始执行。而对于non-blocking assignment而言,所有语句的在一个time step的开始时evaluate,在一个time step结束时assign,从用户的角度看,这些语句是并行执行的。

下面就来讲一下初学verilog的困惑和解决之道:

先贴一下八大原则吧(最后两个原则在可综合的代码编写中将用不到)

  

  (1) 时序电路建模时,用非阻塞赋值

  (2)锁存器电路建模时,用非阻塞赋值

  (3)用always块建立组合逻辑模型时,用阻塞赋值

  (4)在同一个always块中建立时序和组合逻辑电路时,用非阻塞赋值

  (5)在同一个always块中不要即用非阻塞赋值又用阻塞赋值

  (6)不要在一个以上的always块中为同一个变量赋值

  (7)用$strobe系统任务来显示用非阻塞赋值的变量值

  (8)在赋值时不要使用#0延迟

在开始用到verilog时,先接触到了状态机,被一段式,两段式,三段式给弄糊涂了(后面应该会专门有文讲述状态机的编写)。状态机的三个大部分:组合逻辑:次态生成,时序逻辑:状态转移,输出逻辑:状态或者时序。当时疑惑着怎么处理阻塞和非阻塞语句,后在师兄的告诫下,建议采用三段式或者两段式,即将组合逻辑和时序逻辑写在不同的always块中。这样问题就好解决了!

所以,建议1:尽可能的将组合逻辑和时序逻辑剥离,写在不同的always块中,这样原则(4)和原则(5)可以退化到原则(1)和原则(3)。

 

同时,为了让状态输出正确,经常会采用“显性时钟”(我个人这么叫),也就是会采用计数器来指导状态的转移:

 

 这样一来的话由于计数器为时序逻辑,次级状态生成为组合逻辑,如果将计数器写在次级状态生成中会产生比较恶劣的后果,所以根据建议1将计数器单独写成always块。在此也可以引申出第二条建议(如果将计数器的自加看成反馈通路的话):

建议2 : always块中应避免组合反馈回路

疑惑与解决之道将持续更新,以后碰到相应问题的时候即会将问题补充到后面。

 

从硬件的角度上来看,blocking assignment  是顺序流,更适合于建模组合电路;non-blocking assignment 是并行,更适合于建模时序电路。

本节写得比较仓促,不足之处甚多,以后还会陆续补充!

 

原创粉丝点击