当前课程知识点:IC设计与方法 >  3、Verilog语法 >  g)阻塞与非阻塞赋值 >  Video

返回《IC设计与方法》慕课在线视频课程列表

Video在线视频

Video

下一节:Video

返回《IC设计与方法》慕课在线视频列表

Video课程教案、知识点、字幕

刚才我们讲完了always进程里

所允许使用的条件(if)和case语句

下面我们再来看一下这里面

所允许使用的阻塞赋值语句

和非阻塞赋值语句

阻塞和非阻塞的概念

是硬件描述语言所特有的概念

和传统的计算机上的C语言等等

那种纯粹在计算机上执行的概念

是完全不一样的

是新提出来的概念

要理解阻塞和非阻塞语句的的执行效果

也要从两个角度去考虑

一个是当我们写完的硬件描述语言的代码

在计算机上运行的时候

因为这些代码都会

首先在计算机上仿真模拟

它实际上(代表)的电路能实现的功能

是什么样的功能

这个过程称之为仿真

在仿真的时候阻塞和非阻塞有什么区别

有什么差异

第二个就是阻塞和非阻塞

语句所描述的代码

变成真正的电路的时候

他们俩有什么差异

所以我们理解阻塞和非阻塞的时候

一定要从这两个角度考虑

我们来看一下幻灯片

硬件描述语言的赋值语句

不管是阻塞也好 非阻塞也好

我们看它的细节

其实是分两个过程的

首先是赋值语句右边可能有一个

很复杂的表达式

要计算出这个表达式的值

这是第一步

计算出表达式值

第二步是把计算出来的表达式的值

再赋给左边的信号或者变量

所以任何操作、任何运算都有两步

第一个是计算

第二个是赋值

对于阻塞赋值语句而言

也就是说计算和赋值

是要等计算赋值过程全部做完以后

程序或者代码才会执行下一条语句

换句话说

如果有连续三条语句的话

一定要等到第一条语句的计算赋值完成以后

才执行第二条语句的计算赋值

第二条语句执行完以后才执行第三条语句

这个概念跟C语言里的赋值语句是完全一样的

这就是阻塞赋值语句

非阻塞赋值语句是什么意思

也就是说

它把计算跟赋值分开了

如果有连续的多条语句的话

计算过程可以并行的做

但是赋值的话

计算过程是有一个先后的过程的

但是赋值的话

这是在第一条语句的赋值语句

赋值过程还没有执行的时候

第二条语句后续句就开始执行了

所以换句话来说

这个非阻塞赋值语句

它的效果相当于这几条语句是并行执行的

从时间上来说

它们应该是同时开始执行

这是阻塞和非阻塞的定义

这个定义是一个纯语法角度的定义

我们再看一下从工程或者说从实用角度来说

是什么意义呢

或者说有什么要求

第一个在工程里面

通常我们说在一个always块

同一个always块或者说initial块里

或者同一段程序里不允许

或者说不应该混用这两种赋值语句

我到目前为止还没有见过

在任何一个工程代码里面

出现过这两种混用的

虽然在语法上不禁止混用这些语句

但是在工程里

我们要求这两个是不能混用的

第二个 从实现效果来说

通常我们规定:组合逻辑电路设计的时候

用阻塞赋值语句

时序逻辑电路,例如D触发器这样的

电路设计的时候,用非阻塞赋值语句

这是工程的要求

后面两个要求

我们结合到后面的具体的例子

再来说到底怎么做

现在

因为有些概念还没有提出来

可能反而不方便大家对这些概念的理解

所以我们现在先不解释了

我们先来看一下阻塞赋值语句

阻塞赋值语句的符号是等于号

具体的例子我们可以看

这就是一个阻塞赋值语句的例子

刚才已经说了

阻塞赋值语句很像C语言

在上一句执行完之前不会执行下一句

比如说下面这个例子有三句话

一定是等到第一句执行完了

才执行第二句话

它的用处是用来设计组合逻辑电路

一般来说不允许在时序逻辑电路里面

使用阻塞赋值语句

这是工程上的要求

并不是语法上要求

我们来看一下

下面这段代码

这是一段组合逻辑电路

这段电路的功能是什么

对照这三行代码

我们来看一下

首先是把a与上b赋给信号x

然后再把x和b或一下

最后是把a又赋给x

这是阻塞赋值语句

我们说过它跟C语言的顺序执行的概念

是完全相同的

所以我们可以直观地理解

第一句话执行完了以后

x的值是什么

x等于a与上b

或者写成a乘b也行

第一句话执行完了以后再执行第二句话

在第二句话开始执行的时候

这个x的值已经变成了a与上b 对吧

所以x或b就变成了a与上b 再加上b

这个逻辑值

大家应该都能够根据逻辑优化的定理得出

它的值就是b

所以这句话执行完了以后

y的值就是b了

然后再执行第三句话

第三句话的话把a又赋给了x

所以x值是a

所以这样执行完了以后

最终结果是什么

最终结果就是:y的值是b

x的值是a 是吧

这就是顺序执行完了以后最终的结果

我们再仔细看一下这段代码

按照我们前面对组合逻辑电路的定义

对于一个组合逻辑电路而言

它的输入信号是a和b

我们只要写成a或b就可以了

为什么还要“或x”呢

这是硬件描述语言的要求

在这块电路里

x是电路的一个内部信号

它是a与b输出产生的计算结果

产生的一个内部信号

但这个内部信号

又被送回到另一个电路的输入端

作为它的输入信号

也就是说这个组合逻辑电路

实际上它的真正的输入信号还包含了x

从某个角度来说

还包含了x

所以我们在这个地方要

把x也放到敏感表里面

从另一个角度

如果我们要严格地定义敏感表

always后面的敏感表

我们应该这么定义

所有在赋值语句右边出现的信号

所以在赋值语句等号右边出现的信号

我们都要放到敏感表里

如果有if和case语句的话

if和case语句里面的条件信号

也都需要放到敏感表里

这样才是一个完整的

没有错误的组合逻辑电路的描述

我们下面再来看一下非阻塞赋值语句

非阻塞赋值语句的(赋值)符号是小于等于这个符号

具体形式就像这么一个形式

前面我们已经说了非阻塞赋值语句

它把计算赋值号右边的表达式的计算过程

跟赋值过程是分开的

这是第一个特点

第二个特点

赋值语句在执行的时候

相当于这三句话是在并行执行的

相当于是在并行执行

那这是什么意思呢

在以下面这段代码为例

我们来看一下

相当于是赋值语句在执行的时候

always块在执行的时候

这三句话同时在执行

在执行的时候

先把赋值语句右边的

这3个表达式全部计算出来以后

然后再同时分配这3个信号

换句话说

赋值语句在执行的时候

这个always块在执行的时候

到第一句话的时候

把ab的值算出来了

这时候就是a与上b

然后等到执行赋值操作的时候

赋值操作是要稍微等一会才执行的

执行赋值操作的时候

这个a与b计算值就赋给了x

执行第二句话的时候

是把x和b的值去做或运算

这时候x的值是什么

x值到底是什么

是a与上b

还是什么别的值

我们现在还不知道 对吧

还不知道

所以这是一个悬念或者说疑念

我们先放在这

然后再执行第三句话

第三句话是把a的值赋给x

第三句话是把a的值赋给x

我们先写在这

x值就等于a

那从前到后我们看

对x赋了两次值

对y赋了一次值 是吧

对y的这个赋值

我们先不管

先看对x的两次赋值

因为我们对x赋了两次值

一次是赋了a与b

一次是赋了a

在实际操作的时候

是以后一次赋值为有效(操作)

前一次就会忽略掉了

所以最终x的值是a

然后我们回过头来再看这句话

因为x值是a

x最终值是a

所以这些语句执行的结果是y等于a加上b

y等于x(的值)是a

而不是a与上b

所以最终y的值是a加上b

这样的结果

最终的结果就是说

y是a加b x是a

分析的结果和过程好像有一点点诡异

对吧

当然

实际的真实的分析并不像

我刚才这样有点猜测性的分析

实际的真实分析(过程)是一个更复杂的过程

要用到一个基于delta延时的概念

去进行特别精细的分析

才能得到刚才所说的这样的结果

总结一下

如果用非阻塞赋值语句

在这样的组合逻辑电路设计

这种方式去进行描述

你得到的电路结果的值是很难去预测出来的(结果不直观)

或者说很难预期的

这是最终实际的结果

从工程来说

我们就要求在组合逻辑电路设计的时候

大家用阻塞赋值语句

时序逻辑电路设计的时候用非阻塞赋值语句

刚才我们是用仿真的概念

来解释阻塞赋值语句和非阻塞赋值语句

它们之间的差异

下面我们再从最终它们实现的

电路的角度去看一下

非阻塞赋值语句和阻塞赋值语句

它们俩的差异

我们看一下幻灯片

上面是我们刚才列出来的阻塞赋值语句

下面是我们刚才列的非阻塞赋值语句

我们说任何一条语句都对应一个电路模块

都会映射出一个电路模块

实际上的电路

就是这个样子

对于第一条语句

x等于a与上b会映射出一个与门

这个门画的是一个方框

不是特别好看

x的值是a与上b,(所以)映射出一个门

第二个的话是y又是把a与上b以后

在或上一个b

也就是把a与b的这个结果再去或上一个

再去或上一个b

或上一个b 得到输出信号y

这是直接映射出来的结果

第三句话又把a赋给x

所以的话最终x这根线又是从a这里进来

a点进来

所以这是上面这三条语句所得到的电路

在这里面

x这个信号

大家可以把它想象成

是一个临时使用的中间信号

或者说一个临时变量

在这个阶段是一个临时变量

在前两句话的时候

它起的作用相当于一个临时变量

在最后一句话的时候

x(才是)一个真的输出信号

这是直接映射出来的电路

长的样子

下面这种非阻塞赋值的方式

第一句话 a与上b

我们就没法直接按照这种意思理解了

因为这种映射的话

应该说这种执行方式

这种描述方式并不是我们所期望的这种方式

或者说我们所允许的方式

所以映射出来的电路

有时候是很难理解的

在这个电路里

y的值是a或上b

然后x的值会直接从输入端引过去

这是我们根据分析所得到的电路

最右边的这两张图实际上

是软件所产生出来的电路

跟我们分析的结果是一致的

总结一下

或者说小结一下

非阻塞赋值语句

我们一般来说不允许用于组合逻辑电路设计

当你的代码描写的不太好的时候

或者说描述的不太准确的时候

综合出来的电路

或者说实现的结果是难以预测的

我们说非阻塞赋值语句

通常是用来设计时序逻辑电路的

我们再来看一下刚才这样两段代码

如果变成时序逻辑电路的话会是什么样子

时序逻辑电路概念我们还没有讲

我们这大概先看一下

大致先看一下

右边的这个always @

是clock的上升沿,表示在时钟信号的上升沿

表示这段代码对应的

是一些D触发器所构成的电路

这个D触发器的时钟信号是clock信号

在这段代码里

分别把a赋给x

然后x赋给y,y赋给w

每一条赋值语句都会映射出一个D触发器

比如说第一句话

映射出一个D触发器

表示这个D触发器的输入信号是a

输出信号是x

第二句话又映射出一个D触发器

表示它的输入信号是x

d触发器的输出信号是y

第三句话

同样又是一个D触发器

所以下面这种方式会映射出3个D触发器

他们是一个级联的过程

级联的关系

下面这句话

是我们所不建议或者是所不允许的方式

在这种方式里

最终只产生一个D触发器

它的输出信号是w

在这里边x和这个y都变成了一个中间信号

从某个角度来说就变成了中间信号

或者说被优化掉了

被忽略掉了

所以跟刚才的结论一样

非阻塞赋值语句

我们是用于时序逻辑电路设计的

如果在时序逻辑电路的设计里面

用了阻塞赋值语句

最终电路出来的电路形式

有可能是你所难以理解的一种

不可预测的一种电路形式

我们再来看一个实际的例子

用阻塞赋值语句去实现组合逻辑电路

这个描述方式

在我们前面举例的时候已经讲过

前面

我们只是看了代码

没有看具体的电路

在这个电路里面

我们看一下实际产生出来电路是什么样子

大家

要跟着我的思路看一下

电路的分析过程

module表示我们有这么一个电路

它的名字叫test

里面有个输出信号叫dout

dout信号是reg类型

那我们就知道

reg类型信号应该是always块的输出

然后我们(检查),不错

确实是有一个always块的输出信号叫dout

反过头来再去检查的话

dout信号在定义的时候

也应该定义成是reg类型

然后再去看这个always块

我们一看敏感表就知道了

因为是对信号的值判断

所以这块描述的应该是组合逻辑电路

对吧

描述的是组合逻辑电路

然后有一个if语句

表示这里面描述的

应该是一个2选1的多路选择器

根据b的情况

决定把a送给dout

或者是c送给dout

所以这个always块

所映射出来的电路就是右边这个电路

是一个2选1的多路选择器

他的选择信号是b

根据b的值是1的话

把a送给dout

如果是0的话

把c送给dout

我们可以看一下

在这样的语句块里面

要求把if语句的两个分支

既然是组合逻辑电路设计

我们就要把if语句的两个分支都写全了

并且在两个分支里面

都要对dout信号进行赋值

这样

才是组合逻辑电路的描述

我们再关注一下always块的敏感表

按照我们的要求

如果是组合逻辑电路

必须把敏感表里的信号

电路的输入信号

以这条语句为例

电路的输入信号就是赋值语句的右边的

所有信号都要写进去

abc都要写进去

这样

代码的描述才是正确的

如果我们漏掉了一个信号

比如说abc的c漏掉了

那会是什么情况

我们说对电路的理解要从两个层次考虑 对吧

一个是从仿真的角度考虑

一个是从综合的角度考虑

如果漏写了一个信号

这段代码没有违反任何Verilog语言

没有违反Verilog的任何规则

所以这段代码是一段合法的代码

仿真的结果没有任何问题

仿真也可以进行下去

仿真的结果也可能是对的

但是把这段代码送到综合工具

也就是说去产生具体电路的时候

综合工具的检查会更严格

它会检查

输入信号c为什么没有写到敏感表里面

然后综合工具就会给出警告

在相应的窗口里面会给出一个警告

告诉大家这个c没有被放进(敏感表)

这是一个"warning"

不是错误

然后让设计人员去仔细的检查

是不是哪些地方发生了遗漏

这就是我一开头对大家提出的要求

我们在做设计的时候

作为设计人员得特别认真仔细

任何一个遗漏都不能够忽视

在这里面工具给出一个warning

那你就要去检查warning问题

到底是怎么回事

在大的设计里面有可能

软件会给你报告出几百个上千个warning

那我们就得耐心的一个一个去检查warning

如果是一个大的工程项目

通常我们还(需要)填一个文件,填一个表

去写出这个warning为什么可以被忽略

这个warning为什么

可以不用关注就可以往下去走(流程)

将来项目实施下去以后

如果成功了

肯定是没有什么问题

如果错误了 找到原因了

追查到这个表里面

在这个地方warning你没有去仔细检查的话

这个责任就认定是你的问题了

具体到我刚才那个一开头

我说的例子

我们的150万的损失就有人来扛了

在实际使用always语句

或者说实际使用always块

来设计组合逻辑电路的时候

我们通常要避免出现latch

或者说代码设计的不好的时候

有可能会把组合逻辑电路

变成一个时序逻辑电路

什么时候才会出现这样情况?

我们来看一下这个例子

第一个例子

这是一个always块里面用了一个case语句

想设计

作者的预期是要设计一个多路选择器

是一个多位的多分支的多路选择器

那我们看一下

输入信号有什么

输入信号有0 1 2(这些分支)

后面

没有3或者4、5、6、7等等这样的分支 对吧

按照这样的描述

我们前面说了对于case语句

如果有一个分支没有写的话

表示在其他情况下

也就是说D是3的时候

这个值是3的时候

bcd这个值是3的时候

输出信号out要保持原来的值不变

怎么才能保持原来的值不变?

就意味着电路最终

在综合出实际电路的时候

必须增加一些存储单元

也可能是D触发器

也可能是锁存器

因为这是一个电平型的电路

所以产生出一个锁存器

让电路具备了一定的保持功能

才能够跟这段代码的功能一一对应上

不管怎么说

这跟我们作者所预期的方式不同了

预计要实现的电路的性质变了

原来我们预期实现的是一个组合逻辑电路

现在变成了一个时序逻辑电路

所以这段代码就是错的

从工程来说

一个设计人员设计完源代码以后

另一个人检查的时候

通常也是按照这种方式检查

一发现错误

一发现这个地方少一个default

那就不用再去仔细分析了

把这个代码打回去重新修改

因为这段代码肯定是有错的

具体错成了什么样子

就没有意义去关心(分析)了

因为一定要改成正确的才行

下面这段代码 同样

你看这个always @后面是若干个信号的或

所以我们知道作者预期的是

设计人员预期的是要设计一个组合逻辑电路

下面我们再仔细检查if

用if语句设计一个类似2选1的多路选择器

是吧

if的else分支没有写

意味着什么呢?

在条件不满足的时候

out信号要保持原来的值不变

电路就变成这个样子

除了有一个或门之外,产生a或者b之外

out信号还要有一个锁存器

来保存在其他时候的值的不变

所以电路的性质就发生了变化

从组合逻辑电路变成了时序逻辑电路

所以我们说怎么才能避免呢?

避免这种情况

也就是说

我们的case语句的这种默认分支

if-else分支一定要写上

碰到条件判断语句的时候

一定要把所有的分支也都要选上

这是第一种常见的情况

第二种容易出错的情况

对于复杂一点的电路而言

我们在一个case语句里边的某一个分支里面

通常不会只对一个信号进行赋值

换句话说

电路不会只产生一个输出信号

在这个例子里

电路产生了两个输出信号

case分支也都写全了

一共4个分支

bcd的话一共有4个分支

但是在第三个分支里

只对out1进行了赋值

没有对out2赋值

这表示什么意思呢?

也就是说

在4种情况下

out1都有明确的值

但是out2在第三种情况下

它的值要保持原来的值不变

out2要保持原来的值不变

所以最终在out2的电路产生逻辑里面

会存在一个触发器

导致了这个电路的性质发生了变化

所以我们说这段代码也是有错误的

怎么才能避免发生类似刚才这样的错误

我们说

第一种方法就是在case语句里

我们一定要写default分支

保证你无论如何

不管在什么情况下

对你要产生的信号

一定都会有一个固定的值

第二种写法是在case语句之前

在真正进入到case语句之前

先对要产生的输出信号赋一个值

有点像C语言里面对信号(变量)要赋初值

但是注意

通常写的时候是在紧挨着case语句这个地方

对case语句要产生的这些输出信号

在case语句之前

先都赋上值

这个值相当于是在case语句里边

写了default分支

这是两种写法

各个公司或者个工程项目的要求不太一样

我们当然推荐是写这个default写法

当然有些项目里面出于别的原因考虑

或者说仿真和综合的一致性等等各方面考虑

会推荐第二种写法

下面我们稍微小结一下

我们现在已经讲完了

Verilog语言设计的大多数内容

包括怎么定义一个模块

怎么定义信号的端口以及信号的属性

以及怎么设计组合逻辑电路

用两种手段

一个是连续赋值语句

一个是always块设计组合逻辑电路

在always块里

我们又可以用条件判断语句、case语句

以及两种赋值语句

描述电路的内部行为

当然在组合逻辑电路设计的时候

我们只允许用阻塞赋值语句

非阻塞赋值语句

我们要留到时序逻辑电路设计里才用

IC设计与方法课程列表:

课程准备:Quartus II软件的下载

-软件下载说明

--Quartus II软件下载教程

1、集成电路的发展

-a) 集成电路的应用及市场

--1-1集成电路应用及市场

-a) 集成电路的应用及市场--作业

-b)集成电路的制造过程

--1-2 集成电路的制造过程

-b)集成电路的制造过程--作业

-c)从CPU的发展看IC的进展

--1-3从CPU的发展看IC的进展

-c)从CPU的发展看IC的进展--作业

-d)从行业的发展看IC的进展

--Video

-d)从行业的发展看IC的进展--作业

-e)从ISSCC看IC的发展方向

--讲课视频

-e)从ISSCC看IC的发展方向--作业

2、数字集成电路设计方法

-a)数字系统的实现方法 (ASSP/FPGA/ASIC的对比)

--讲课视频

-a)数字系统的实现方法 (ASSP/FPGA/ASIC的对比)

-b)组合逻辑电路

--Video

-2、数字集成电路设计方法--b)组合逻辑电路

-c)时序逻辑电路(1)

--2-3时序逻辑电路的设计方法 (一)

-d)时序逻辑电路(2)

--2-3时序逻辑电路的设计方法 (二)

-2、数字集成电路设计方法--d)时序逻辑电路(2)

3、Verilog语法

-a)Verilog的历史和学习要点

--讲课视频

-b)端口、信号及数据类型

--讲课视频

-b)端口、信号及数据类型--作业

-c)逻辑电平及数据操作

--讲课视频

-3、Verilog语法--c)逻辑电平及数据操作

-d)Assign 语句

--3-1-4assign语句

-e)Assign 举例

--3-1-5 Assign 举例

-f)Always

--3-1-6 Always

-f)Always--作业

-g)阻塞与非阻塞赋值

--Video

-3、Verilog语法--g)阻塞与非阻塞赋值

-h)D触发器的描述

--Video

-i)时序电路的设计

--Video

-i)时序电路的设计--作业

-j) 面向测试的Verilog语法(1)

--3-3-1面向测试的Verilog语法(1)

-k) 面向测试的Verilog语法(2)

--3-3-2 面向测试的Verilog语法(2)

-k) 面向测试的Verilog语法(2)--作业

4、电路设计实例

-a)电路设计实例1

--Video

-b)电路设计实例2

--讲课视频

-b)电路设计实例2--作业

-c)电路设计实例3

--讲课视频

5、Modelsim仿真工具

-Modelsim仿真

--Modelsim仿真

6、Quartus工具

-a)综合及相关基本概念

--Video

-a)综合及相关基本概念--作业

-b)综合及优化

--Video

-c)门级仿真

--门级仿真

-d)Quartus综合及分析(1)

--讲课视频

-e)Quartus综合及分析(2)

--讲课视频

-e)Quartus综合及分析(2)--作业

-f)Quartus综合及分析(3)

--Video

-g)Quartus综合及分析(4)

--Video

-g)Quartus综合及分析(4)--作业

Video笔记与讨论

也许你还感兴趣的课程:

© 柠檬大学-慕课导航 课程版权归原始院校所有,
本网站仅通过互联网进行慕课课程索引,不提供在线课程学习和视频,请同学们点击报名到课程提供网站进行学习。