当前课程知识点:IC设计与方法 >  3、Verilog语法 >  k) 面向测试的Verilog语法(2) >  3-3-2 面向测试的Verilog语法(2)

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

3-3-2 面向测试的Verilog语法(2)在线视频

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

下一节:Video

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

3-3-2 面向测试的Verilog语法(2)课程教案、知识点、字幕

在描述正式的testbench之前

我们还要再接触一些新的Verilog语法知识

在进行电路测试的时候

通常我们会用到一些Verilog所定义的

系统任务和函数来观测电路的输出

控制电路的行为

最常见的大概有这四类

大家注意

在这四类语句之前都有一个$符号

凡是$符号打头的这些语句

都表示是Verilog系统所定义好的

任务和函数

我们可以直接调用

最常见的有这四大类

第一个是$time语句

用来显示当前的时间

仿真器当前已经运行到什么时刻了

第二类是$display和$monitor语句

用来显示或者说观测我们所需要关注的

信号

第三类($stop)是让仿真器能够停止下来

暂停下来

第四类$finish语句

是让整个仿真器完全停止下来

在实际的物理电路设计的时候

一般来说是不允许使用延时语句来描述电路的

时间特性的

但是在仿真的时候

我们需要描述电路的时间特性 时序特性

例如我们需要描述时钟周期信号

时钟clock信号的周期

它的频率等等这些特性

描述复位信号的时候

我们(需要)定义复位信号的脉冲

到底在什么时刻发生

所以这时候我们要用到

Verilog一个新的语法知识

#符号

#符号是Verilog所定义的

用来描述延时相关的特征的

我们来看几个例子

#在Verilog里有多个用处

一个是在测试的时候

我们可以用这样的形式表示

复位信号rst=1是在10个时间单位后

注意这里面不是绝对时间

是10个时间单位之后

把复位信号变成1

用这种方式来描述一些信号的物理延时

第二个是在元件例化的时候

我们可以用一个#号来表示实际元器件的延时

第三种情况是

用#号也可以实现元器件参数的传递

反单引号是Verilog所定义的一些特殊的语句

以便我们的代码去包含一些其它的语句段

或者定义一些常量

常见的反单引号大致有这四类

我们在这门课里面只简单地介绍常见的

例如`define语句

用来定义一些特殊或者说定义一些常用的常数

`include语句用来包含一些Verilog语句段

一些在整个项目工程里边都会用到的Verilog语句段

我们可以把它写在一个单独的文件里

然后用`include把它包含进来

`include语句的效果就相当于

把另一个文件完整的拷贝到这个文件里面来

`timescale刚才已经说了

描述电路的时间特性

`resetall用来把所有的

编译引导恢复到缺省状态

我们来看一下`include语句的例子

下面是三个简单的例子

例如我们在一个project里

通常会有好多Verilog文件

分别描述不同的模块

如果在这些Verilog文件里

都用到公用的常数

公用的参数以及公用的定义

那么我们可以

把它写到一个公用的global.v文件里面

然后用这条语句把它包含起来

另一种方式

就是把我们电路下面的一个子电路

整个包含进来

例如我们可以把

某个counter.v包含到当前设计里面来

第三种情况是我们的设计用到了一些底层的

库文件

在ASIC设计里面

经常会用到一些底层的库文件

我们可以直接把库文件

包含到我们这个文件里面来

这是`include的三种常见用法

最后我们再来详细看一下`timescale语句

刚才已经说了

`timescale是用来描述我们的

代码里面的时间单位

以及仿真的精度的

通常`timescale是放在代码的第一行

我们来看一个具体的例子

在这个例子里

`timescale描述了电路的仿真的单位是10个ns

仿真的步长是1个ns

我们再来看具体的例子

例如在这个例子里

用了一个#号

它的单位是2.33

表示这个与门的延时是2.33个时间单位

2.33个时间单位代表的

实际的物理意义是什么呢

我们就要把2.33乘以一个时间单位

我们得到的数字是23.3

也就是说

这个与门的真实的延时是23.3ns

由于我们设的仿真精度是1个ns

所以四舍五入以后

这个与门的实际延时是23ns

通过这种方式

Verilog在每一个门的描述的时候

定义的是一个抽象的时间

然后通过时间单位和时间精度

可以描述出具体的准确的时间

下面我们再来看一下counter设计

也就是说我们的被测设计

在这个被测设计里

我们定义的counter有三个(输入输出)信号

有时钟信号 复位信号以及输出信号

时钟信号和复位信号是输入信号

输出信号是out

是一个4位的信号

由于这个4位的

输出信号out是一个always语句产生的

所以我们要把它定义成reg类型

这个电路是一个时序电路

在时钟的上升沿工作

复位信号是一个低电平有效的复位信号

所以先判断复位信号

当复位信号有效的时候

计数器被清零

复位信号无效的时候

每一个时钟有效沿

也就是时钟上升沿计数器加1

这就是一个非常简单的

具备低电平有效的异步清零的“加计数器”

我们再来看一下

怎么在testbench里测试这个电路

testbench的第一部分

描述了时间特性

也就是我们这个仿真的时间单位是1个ns

也就是说我们后面代码里所有的

跟时间相关的常数

它的单位都是1个ns

第二个是我们仿真的精度是1个ns

我们的测试平台起的名字叫top

它没有任何输入和输出信号

这一段Verilog代码是

和我们前面测试平台的那张图是一一对应的

在测试平台里面底层里面一共有三根信号线

是时钟、复位和dout

时钟和复位信号

我们应该定义成什么类型呢

取决于这两个信号是怎么产生的

在我们这段代码里

我们看一下右边

rst信号和左下角的clk信号

都是由initial块产生的

所以我们在定义的时候

需要把它定义成reg类型

dout信号在刚才的counter里

dout信号是由一个always块产生的

所以在counter里

它是定义成reg类型

但是在这个电路里

dout信号是是由一个元件例化语句产生的

并不是always

或者是initial语句来产生的

所以我们这里就把它定义成wire类型

这跟我们上节课讲的

在RTL电路设计里面的规则是一样的

我们观测一个信号到底需要定义成reg类型

还是wire类型

只需要去观测在当前这个层次

它到底是由谁产生的

只有initial

或者always语句产生的信号

我们才需要把它定义成是reg类型

这是前面这部分

信号的定义

再下一部分是元件例化

把我们的被测设计例化出来

采用元件例化语句

把counter例化成uut

然后它的三个信号依次连接到电路板上的

这三个信号上

再往下我们就要产生clk信号和复位信号(rst)了

在这里边我们用到了一个新的语句叫forever

顾名思义

是一个循环语句

这段代码我们可以看一下

它是一个类似于八股的代码

用来产生一个周期信号

首先为clk赋初值0

在0时刻的时候给它赋一个0

然后用循环语句

每过10个时间单位

clk取非

也就是说原来是1就变为0

原来是0就变为1

这段语句

直觉上大家就可以猜的出来

它用来产生一个时钟周期

是20个时间单位的clk信号

高电平10个时间单位

低电平也是10个时间单位

所以大家就知道了

任何一个电路

如果要产生时钟信号

就可以用类似这段代码来产生

然后通过修改这个数值

就可以改变时钟周期

通过修改前面这个值

就可以设置时钟的信号的初值是0

或者是1

这是周期信号

对于非周期信号呢

我们用这段代码来产生

复位信号

一开始的时候它的初值是1

经过15个时间单位以后

注意我们这里边用的是阻塞赋值

所以下一条语句是经过15个时间单位之后

才把复位信号置成0

因为是阻塞赋值语句

所以要再经过10个时间单位之后

赋值信号才变成1

然后再经过175个时间单位之后

$finish让整个仿真器停下来

也就是说仿真器在全部加起来

大约是200个时间单位之后

仿真器就能够停下来了

这段语句不但能够产生复位信号

还能够控制仿真器在所有的

信号结束之后停下来

所以用这两段语句

为我们的电路产生了电路所需要的

两种输入信号

最后是一段代码

用来观测电路的输出

前面我们说过

观测电路的输出

可以用两类

一类是用$display语句

另外一个是用$monitor语句

$monitor语句表示观测哪几个信号

在这里面我们可以看到

我们观测了rst、clk和dout

并且按照指定的格式显示出来

这条语句的

格式和C语言里面的

printf的格式是完全一样的

我这里面就不多说了

这条语句的意思就是说

在任何时刻只要这三个信号的值发生了变化

都按照这种格式

把这三个信号的值显示出来

这段代码我们可以看到

就是完整的测试平台的描述方式

例化元器件

为电路产生输入信号

以及指定观测哪些输出信号

这就是一段标准的Verilog代码

测试平台的代码

在这段代码里面出现了initial和always

下面我们再来看一下initial跟always的区别

always表示它所包含的这段代码会始终循环

不断的执行

initial语句正好相反

它从头到尾只执行一遍

所以initial语句通常只用来干几件事情

第一个是用来产生激励信号

因为它只执行一次

所以可以用来产生前面我们所看到的非周期信号

或者是脉冲信号

第二个initial语句

可以用来指定检测哪些输出信号

第三个我们后面还会说

initial语句还可以用来为某些信号赋一些初值

always语句通常要么用来检查电路的输出

要么用来产生周期性信号

或者用来设计RTL级的代码

我们来看一下怎么用initial语句来产生信号的初值

对于左边这段代码

这段代码就是我们刚才所说的计数器

我们用了一个异步复位信号

rst信号来为计数器赋一个初值

当rst信号有效的时候

初值置成0

对于这段代码

我们必须要为电路设计一个复位信号

实际在工程上

有时候为了使电路的输入端尽量的少

有时候电路的输入信号都没有

这样的电路制造的时候因为少了一个输入端

电路的成本会适当的有所降低

对于性价比要求比较高的电路而言

这种电路方式有它的优势

如果没有这段代码

没有这个复位信号

我们的计数器就变成了右下角这段代码

只有四行(代码)的计数器

这个计数器也能完成正常的计数工作

它也能够从0计到最大值

然后再返回到0

再继续计数

从某种角度来说

这个计数器也是能够正常工作的

但是这样的计数器

在仿真的时候就会出问题了

在仿真器仿真的时候

在物理的绝对的0时刻

这个计数器的初值是不确定的

在物理的绝对0时刻

计数器的初值有可能是从0开始计数

有可能是从1开始计数

对于一个实际的计数器

不管是从0还是从1(开始)

都不是问题

只要它能够循环往复的计数就可以

但是在仿真的时候就有问题了

如果是从0开始计数

它是一种表现情况

从1开始计数就是另一种表现情况

所以仿真器只能判定当前计数器的值是不确定的

是X

然后由于初值是X

所以计数器的以后

整个时刻(轴)上

计数器的值都是X

就会导致我们的仿真器

无法验证这个电路是不是能正常工作

所以我们就要采用一种手段

让仿真器能够工作起来

这就是用initial语句

我们可以用initial语句人为的

为这个计数器赋一个初值

让仿真器能够正常的工作

所以我们总结一下initial语句它的

用处仅仅是为了让仿真器能够正常工作

而对实际的物理电路没有任何的影响

这是initial语句的一个用处

下面我们再来看一下

激励信号产生的几种方式

我们说了

时钟信号可以用左边的模板来产生

在初始的时候

为时钟信号赋一个初值

然后周期地每工作10个时间单位是高电平

再10个时间单位是低电平

所以用这种方式产生

周期是20个时间单位的时钟信号

结合`timescale语句

我们可以描述出比如20ns

或者是其它周期的时钟信号

对于非周期信号

例如复位信号

或者说电路所需要的一些其它信号

比如说控制信号

或者是数据信号

都可以采用下面的这些代码段来产生

在刚才我们的例子里

我们采用的是用阻塞赋值语句

加上延时语句来产生非周期信号的方式

在这个方式里

我们可以看到

所有的延时

这里面的15、10和175

指的是相对于代码开始执行的时候

或者说相对于0时刻的相对时刻

指的是相对时刻

我们以10为例

是指相对于当前时刻而言之后的时间

所以我们说这里面时间都是相对时刻

用initial语句的最常见的一种方式

第二种方式

有时候用相对时间

如们相对时间非常多

那么很难去算

或者说算起来不太方便

有时候我们描述信号的绝对时间

比如我们描述这张图的时候

我们可以描述在15ns的时候

产生一个脉宽是10ns的复位信号

这是一种描述方式

另一种描述方式

我们可以说

在15ns的时候

把复位信号置低

在25ns的时候

绝对时间25ns的时候

复位信号置高

然后在绝对时间是200ns的时候

仿真器结束运行

如果是用这种方式来描述的时候

我们希望是用一种绝对时间来描述它

那么这时候我们可以用fork-join这种语句

如果initial后面的begin和end换成fork和join

表示这里面的fork和join之间的

所有语句都是在同一时刻运行的

所以这段代码就变成了

在0时刻执行第一条语句rst置1

然后在0时刻执行第二条语句

也就是说相对于0时刻而言

在第15个时间单位的时候

把rst置0

然后在相对0时刻而言第25个时间单位的时候

把rst信号置1

从0时刻开始算起

第200个时间单位的时候

仿真器结束运行

这是第二种方式

第三种方式

是用非阻塞赋值语句

前面我们都是用的阻塞赋值语句

如果用非阻塞赋值语句

那么我们是用这样的描述方式

我们把延时的描述

放在赋值号的右边进行描述

这也是一种描述方式

在这种方式里边

由于非阻塞赋值语句的几句话都是同时运行的

所以在这里面的延时也是表述的绝对时刻

这是常见的三种方式

表示非周期信号的方式

大家可以任选一个你所喜欢的方式来使用

在读代码的时候

我们可能三种方式都会遇到

最后我们再来看一下

如何检查电路的输出

我们说可以用$monitor语句

或者说$display语句来检查电路的输出

在这个initial块里边

我们用的是$monitor语句

我们说了$monitor语句

是指当我们所要观测的

信号只要发生变化的时候

都会显示出电路的输出

所以它的输出是这样的情况

在0时刻的时候

(信号)发生了变化

0时刻的时候或者说电路的初值都会显示出来

然后在1时刻的时候

某一信号发生了变化

out发生了变化

所以会把out和in的值都打印一遍

然后在10时刻的时候

in的值发生了变化

所以又打一遍

也就是说

只要信号有变化

只要被观测的信号发生了变化

那么仿真器都会把相关的信号显示出来

$display语句和$monitor语句相比而言

它只是显示在当前时刻的信号值

换句话说$display语句只会执行一次

所以右边这段代码

只会执行一句

这样看来

好像$display语句没有什么太大的意义

$display语句主要的

作用是可以结合延时语句同时工作

它可以指定

比如说在前面加一个延时语句

后面可以再加延时语句

再运行同样的$display

这样就可以实现在指定的时刻观测信号

这样$display语句

如果加上一串的延时语句之后

就可以指定比如说在10ns的时候

观测一次信号

在100ns的时候观测一次信号

在150ns的时候再观测一次信号

就实现了可以在特定时间观测特定信号

前面$monitor语句有点像

在盲目的观测所有的信号

最后我们再总结一下和测试相关的语法知识

我们说

一个是元件例化

可以把被测电路例化到我们的

测试平台里面去

第二

我们可以用initial语句

或者是always语句观测

设置激励信号

产生复位信号 时钟信号

所需要的数据信号

也可以用

initial语句和always语句结合

$monitor、$display语句观测电路的输出

最后我们可以用$finish语句停止仿真

在服务器上运行这样的仿真程序的时候尤其重要

如果我们不用$finish去停止仿真器的运行

仿真器会不断在那运行

耗费CPU的资源

只有用$finish语句

或者手动停止的方式才可以把CPU释放出来

把CPU释放给其它使用服务器的同学

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)--作业

3-3-2 面向测试的Verilog语法(2)笔记与讨论

也许你还感兴趣的课程:

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