当前课程知识点:IC设计与方法 > 5、Modelsim仿真工具 > Modelsim仿真 > Modelsim仿真
前面我们讲了怎么做RTL级的设计
以及怎么写一个testbench
对RTL级的设计施加激励
以及观测它的输出
完成这样的设计以后
我们下面就要在计算机上
模拟这个设计
看看我们写的代码的功能
是不是符合我们的预期
这就要用到一系列的仿真工具
我们来看一下
我们常用的仿真工具都有什么
目前常用的EDA仿真工具
主要有三家集成电路公司提供
一个是SYNOPSYS 一个是Cadence
第三个是Mentor Graphics
这三家EDA公司的仿真工具占据了主要的市场
其中SYNOPSYS仿真工具的名字叫VCS
Cadence的仿真工具的名字叫NC-Sim
Mentor Graphics的仿真工具叫Modelsim
幻灯片上的下两家仿真工具
主要在LINUX服务器的平台上运行
Modelsim仿真工具
主要在PC平台上运行
对于初学者而言
大家用的仿真工具主要是Modelsim这个工具
这里面我们提到了操作系统
目前来说进行EDA仿真
或者说EDA的设计
用的操作系统主要有两种
一种是基于WINDOWS平台的
一种是基于LINUX平台的
对于基于可编程逻辑器件
例如CPLD 或者是FPGA的设计
由于操作软件
或者说进行验证的工程师
主要都使用WINDOWS平台
所以大家在用仿真工具的时候
主要还是用基于WINDOWS平台的
Modelsim来进行仿真验证
对于ASIC设计
或者是专用集成电路设计
因为大多数的除了仿真之外的其它工具
基本上都是支持LINUX平台的
所以 我们主要的仿真工具
或者说验证工具以及其它的EDA工具
都是在LINUX平台上运行的
这里面提到的Modelsim和NC
这两个工具都有跨平台的功能
它们既有WINDOWS版本
也有LINUX版本
VCS主要只支持LINUX版本
对于ASIC设计人员来说
或者说将来大家想更专业的
去学习某一个工具或者某个软件
我们倾向于
如果有机会的话
尽可能去使用NC或者是VCS
去熟悉一下比较专业的软件
由于我们课程的软件的license等等问题
因为我们只能用到教学的软件版本
所以目前在我们这门课里面
还只能使用Modelsim
在我们后续的幻灯片里面
我们用的例子是Modelsim
自带的一个八位加计数器的例子
例子可以从Modelsim安装目录下的
这个位置去找到
对应的是一个RTL级的设计
和我们上节课讲的计数器的例子是相似的
另外一个是针对这个RTL级设计的测试平台
tcounter.v这个Verilog文件
在我们的counter.v这个测试文件里面
和我们前面的例子相对来说
这个例子就复杂一点
在我们前面的计数器例子里面
只是完成一个加计数器的动作
在这个计数器里面还增加了一定的延时
我们在后面的仿真波形里面可以看到
所有的动作会有一定的延时
用来模拟门电路里面的D触发器
和基本门电路所具备的基本延时
Modelsim除了提供用于仿真验证的
基本的源代码之外
另外还有一些内嵌的非常简单的教程
大家可以从Modelsim相应的菜单下里面
找到教程
也可以找到整个软件的用户使用手册
如果要学习Modelsim的更高级的功能
可以去查找相关的用户学习手册
另外在网上也有一些中文版的教程
对Modelsim的高级功能解释的比较清楚
大家也可以从里面学到更多更高深的知识
我们来看一下具体仿真验证的步骤
通常来说
仿真大概有这几个步骤
首先我们要设置环境
包括在软件里面设置相应的工程环境
设置相应的库文件
用到了哪些库
所谓的库就是我们的代码里面
都使用到了哪些别人已经做好的设计
设置好环境以后
第二步就是编写Verilog源代码
编写代码既可以用大家熟悉的
文本编辑工具来做
也可以用Modelsim提供的代码编辑工具
Modelsim提供的代码编辑工具
对于RTL级代码里面
或者是测试代码里面
用到的Verilog的关键字
可以用特殊的高亮颜色显示出来
方便我们去看代码的层次是不是清楚
以及代码里面是不是有一些
显而易见的语法错误
完成RTL级代码编写以后
下一步就是编译
编译的目标是把我们所写的
Verilog语言的代码变成计算机上
可以执行的一个程序
然后执行仿真的过程
就是在PC机上运行这个程序
来模拟我们的电路所执行的过程
仿真过程的术语就是simulate
仿真完了以后
作为我们设计人员
很重要的一步就是我们要分析仿真的结果
去检查电路的结果对不对
是不是符合我们预期的设计目标
检查的手段有多种
最直接的办法就是用波形的方式去检查
还可以用一些更高层次的
比如说数据流图 有限机等等方式去
从高层次的角度
来分析我们的电路是不是有问题
或者用一种比较高效的追踪方法
去定位故障所发生的地方
这就是仿真的过程
当我们把源代码写完以后
我们就要用编译把我们的RTL级的源代码
包括测试平台的代码编译成
计算机上可以运行的程序
编译完了以后呢
我们作为设计人员
一定要去检查编译的过程中是不是有错误
或者warning
在Modelsim里面有一个Transcript窗口
一般位于软件的最下方
其它的NC也好 VCS也好
这些工具都有相应的命令行的窗口
用来显示编译过程中出现的警告和错误
我们作为设计人员一定得去详细的检查
对于错误
我们一定要去找源代码里面的错误
到底是什么原因
然后怎么去修改它
对于警告,要注意的是
我们作为设计人员一定不能忽略
前面我们给大家讲过
集成电路的设计人员要求必须非常的细心
任何一个错误
或者是警告都不能忽略
因为有可能你忽略了一个小的错误
有可能会造成最终
做出来的电路有很大的隐患
造成你做出的芯片是错误的
可能会产生很大的经济损失
所以我们任何错误都不能放弃
我们看一下
在这个例子里面
根据编译的结果可以看到
这里面有红色部分
表示我们的设计有错误
然后我们打开详细的报告
有一个详细的报告
在详细的报告里面
我们从前往后查
注意一定要从前往后查
去找是不是有Error 或者是Warning
在这里面报告出了一个Error
Error是在counter.v的第38行有一个错误
第38行报告说有一个双等号的这个地方
出现了一个语法错误
语法错误是两个等号它不认识
回过头去我们定位到源代码
这个源代码编辑器
就是一个采用了Verilog语法的编辑器
里面所用到的所有的关键字
Verilog的关键字
都是用相应的红色
或者特殊的其它颜色表示出来
对应的我们看第38行
在38行里面
在复位信号有效的时候
对count赋值
应该是用小于等于号(<=)赋值
这里写成了两个等于号是错误的
所以
用这种方式大家回顾一下刚才的流程
我们要详细地检查编译软件
给我们报告的错误
或者Warning
然后根据给出的错误或者Warning
在源代码里面定位
去修改相应的语法错误
注意 软件的分析
它跟我们人的分析的过程
通常不是一一对应的关系
所以 有时候软件报告给我们
第38行错的时候
(我们)不一定会在第38行找出错误
因为我们这里面给了一个非常简单的
是我人为的给出的一个错误
错误在这个地方
所以能够直接定位到第38行
有时候软件定位在38行
实际错误是发生在38行之前的
这是一个(方面)
第二个(方面),当我们检查错误报告的时候
我们要从头往下查
尽量不要从后往前查
因为有时候最前面的第一个错误
一旦改正了以后
后面的所有的错误自然而然都消失了
如果我们只盯住后面的错误
反而不容易找到错误的真正来源
所以要注意
一定要从前往后去检查错误是如何发生的
当我们修改完错误以后
正确的的编译完了以后
下一步就是进行仿真了
我们启动仿真工具以后
Modelsim工具就会给我们显示出
设计的一种树状表示方式
对于我们设计里面的每一个实体
每一个module以及每一个进程
每一个always块
或者是initial块
软件都可以用目标的方式
或者是用对象的方式列出来
我们来看一下这个测试
首先顶层是一个test_counter
就是我们的测试平台
在这个测试平台下面
有一个DUT
有一个被测设计
以及三个进程
在我们的test_counter平台里面
这次给大家展示的测试平台里面
有三个initial块
分别用来产生时钟信号 复位信号
以及相应的其它的动作
所以在这里面用一个树状结构
把我们的设计层次逐渐的展开了
在DUT前面有一个加号
我们还可以点这个加号
DUT的这个层次结构
进一步的去展现出来
在软件的右边会有一个Objects窗口
这个窗口里面列出了在当前设计层次下面
都有哪些对象我们可以去观测
所谓的对象就是有哪些信号
有可能是电路的输入输出信号
也有可能是电路的内部信号
在test_counter这个层次
也就是顶层的层次
有电路的时钟 复位和计数器的值
我们可以选择这三个信号
进行相应的观测
具体软件怎么操作
在我们上课的时候就不说了
大家可以针对实验指导书
或者针对软件的使用教程
去学习怎么操作软件
我们在上课的时候主要还是讲
这里面所设计到的一些基本概念
打开仿真工具以后
我们要进行仿真了
在仿真的时候呢
我们要干什么事呢
我们要干这里说的这几件事情
首先我们要能够控制仿真工具的运行
让它运行指定的时间
或者说重新启动等等这些操作
所以我们大致有这四类东西是需要掌握的
不管你是用Modelsim
还是用NC 还是用VCS
或者是其它的相关的软件
大致都需要掌握这几类对仿真的控制
一个是restart重启
有时候我们仿真完了以后
或者在仿真过程中会发现
需要修改源代码
或者需要人为地改变某一个信号的值
或者说在仿真的时候观测波形太长了
我希望去控制这个仿真器重新开始
第二个是指定仿真时间
我们前面讲写testbench的时候讲过
如果在testbench里面
我们不用$finish
或者是$stop这样类似的系统函数
去控制仿真工具的话
仿真有可能会无穷无尽的执行下去
这样既会造成CPU资源的浪费
也会在仿真的波形窗口里面
显示的时间过长
导致我们没法看到所观测的事件
所以我们要指定仿真运行时间
比如说我们在这里面可以输入200纳秒
然后让仿真器每次
每按一次这个键只运行200纳秒时间
这样我们可以一步一步
观测电路执行的结果
也可以用相关的按钮
这个按钮
让仿真器持续的运行仿真
直到碰到$finish这样的命令
让仿真器停下来
如果我们的testbench里边
没有相应的停止仿真器的控制命令
或者系统函数
我们就不得不人为地
按Stop按钮让仿真器停下来
否则它就会无穷无尽的仿真下去
这就是对仿真的控制过程
当仿真器执行完相应的仿真工作以后
下面就是我们设计人员要做的事情了
我们要检查
电路运行的结果是不是正确
怎么检查呢
通常最常见的就是用波形窗口
我们用波形窗口来观测
电路输出的波形对不对
在波形里面我们要检查这几类信号
一个是输入信号
常见的输入信号有三大类
时钟信号、复位信号和数据信号
我们要检查这些输入信号加的对不对
因为有可能我们写的testbench
产生的这些信号不合适
也会导致电路出现的结果不正确
对于时钟信号我们通常检查的是
时钟信号的周期和频率
比如说在这里面
时钟信号 我们可以看到一个周期是20纳秒
我们通过这种方式可以去检查一下
时钟信号的周期对不对
时钟信号的高电平持续时间
和低电平持续时间对不对
以及我们在0时刻期望时钟信号
是什么样的值
这是我们所要关心的几个细节
第二个需要检查的信号就是复位信号
我们要观测复位信号的有效脉冲
是不是我们期望的有效脉冲
对于这个复位信号
我们可以看出
这应该是一个高电平有效的复位信号
也就是说
我们要观测第一个复位信号的电平
是不是对的
不排除有时候
我们会把复位信号的电平给加错了
第二个 我们注意一下
复位信号的两个沿
上升沿和下降沿
通常来说这两个沿
必须跟时钟信号的沿能够错开
这也是我们对于D触发器类的
存储电路的要求
如果复位信号的变化沿
跟时钟信号的变化沿重叠了
那电路的行为是不可预测的
所以这是我们在写testbench的时候
一定要注意的
要把复位信号有效沿跟时钟沿错开
这种加法
在幻灯片上的这种加法
是一个比较简单的复位信号
有时候为了模拟真实世界的复位信号
我们会把复位信号的释放沿往后挪
挪到一个时钟周期之后
在第二个时钟周期
或者是第三个时期周期才释放
这跟我们的物理世界(的现象)是比较一致的
第三个就是数据信号
在我们这张图里面
没有给出数据信号
实际的数据信号
跟复位信号是相类似的
我们在施加数据信号的时候
一定也要注意
数据信号的变化沿
也一定要跟时钟的有效沿
哪怕是无效沿也要尽可能错开
以免我们后续的电路在理解
在相关的沿采数据的时候
采集不到稳定的数据
严重的会造成RTL级的仿真
和后面的门级仿真结果会不一致
这是我们要观测的三种输入信号
除了这三种输入信号之外
我们还要观测电路的输出信号
另外还要观测电路的内部信号
所谓的内部信号
通常就是我们电路的状态机
我们要观测状态机
在整个电路工作的时间里
它是怎么转移的
所以我们要观测状态机的状态信号
对于电路内部
可能还会存在一些控制信号
一些关键的控制信号
我们也需要去观测它
对于电路的输出信号
我们要去观测它
那么以这个电路为例
我们的输出是一个计数器的输出值
我们可以看到
计数器的输出在32ns的时候发生了变化
从1变到了2
相对于时钟的信号
时钟的上升沿是30ns
所以相对于时钟的上升沿有2ns的延时
这个2ns的延时是怎么产生的
是在我们的这个RTL级代码里面
为了模拟一个真实的D触发器
我们在赋值语句里面人为的
增加了一个2ns的延时
大家感兴趣的话
可以去检查一下相关的RTL级代码
如果在RTL级代码里面
像前几节课讲RTL级设计的时候
相应的赋值语句没有延时
那么这个输出的counter的变化沿
和时钟沿就几乎是完全对齐的
这时候的延时是零
是一个非常理想的器件
这就是我们要观测的输出信号
我们要注意观测信号是在什么时候变化的
以及信号的变化时间
是不是和我们的预期是一致的
对于类似这样的counter的计数型的信号
我们一般来说
除了要观测它是不是在正确的翻转
也要观测它到某个特定的时候
翻转到计数最大值的时候
是不是能够回到正常的状态
正常的初始状态
这是我们观测的
除了观测波形
或者说为了观测波形
我们要有哪些手段
去改变我们的观测目标呢
我们可以看到有时候
我们仿真的窗口显示的波形非常的密集
我们很难直接观测我们所要观测的区域
通常我们的观测区域
只是整个波形窗口里面的一个极小的区域
所以我们在波形窗口里面
涉及到一些对观测信号
操作大致有几类操作
首先是总线信号的展开和收缩
例如这个counter
我们要观测的counter是一个总线信号
我们点前面这个加减号
可以把总线展开
观测总线中的每一根线
在RTL级设计里面
这个意义并不是很大
但是在门级设计里面
意义就比较大了
因为对于一个总线信号
它的八位数据线
例如这里面是一个八位信号
它的八位数据线的变化时刻
通常不是同时变化的
我们对八根信号线分别观测
就能够看出这些信号变化的先后次序
对于某些关键路径而言
就非常有意义了
第二个是数据的显示方式
对于一个二进制计数器
我们对于数的计数结果
除了可以用二进制方式显示之外
还可以改变计数的显示方式
比如可以用八进制 十进制 十六进制
或者是其它方式进行显示
另外对于数的计数结果
我们除了用数值的方式显示计数结果
还可以用模拟波形的方式显示
如果计数器要输出的是一个正弦波
或者是三角波
我们可以用这个方式去观测
很直观的观测输出的波形是不是正确
第二类就是波形的放大缩小
通常用于观测一个局部信号
在这里面有这么一个按钮
这个按钮可以只放大
以光标为基准点
放大光标处的波形
用这种方式去放大
避免了全局放大和全局缩小
造成图像的飘移
再往下就是光标操作
作用是可以在我们的图形上
设置若干个光标去测量
不同的事件之间发生的时间(差)
这是基本的一些数据显示
和放大缩小的操作
往后有几个比较有用的操作
是用于去寻找一些特定的信号
比如说我们在观测这个reset信号的时候
我们可以看到reset信号
只在刚开始的时候有一个小的脉冲
在很多其它时刻都没有
那如何在一个很长的时间范围内
比如说我们的仿真持续了一秒钟
reset信号只持续了10个纳秒
你要在一个很长的波形里面
去寻找这一个脉冲
怎么去找呢
我们可以用到这里面的这几个按钮
这几个按钮可以让光标快速的
跑到某一个信号的事件
比如说这个信号发生了下降沿(事件)
或者说这个信号发生了上升沿(事件)这个位置
我们只要选中相关的信号
按相应的按钮就可以让光标直接定位到
我们所观测的信号变化的事件上
这样定位的速度会非常的快
第二个方法是搜索特定的信号的值
例如计数器
举个例子
我们只关心计数器计数到15的时候
看它发生了什么情况
我们可以在这里面直接输入15
然后让光标直接跳到计数器的输出值
已经是15的时刻
就能够快速的定位在这个时刻发生的故障
最后一个功能
也是我们常用的功能
在我们这个设计里面
我们所观测的信号非常的少
因为只有时钟复位和计数值
对于一个复杂的设计
我们要观测的信号可能有上百个
复杂的设计的内部信号可能有上千个
一般来说我们不会把所有的信号
全部添加到观测窗口里面
这样会显得信号非常的凌乱
我们的一个做法就是
我们先观测要观测的关键信号
例如是一个输出信号
当发现这个输出信号不对的时候
我们有可能(想)看到底是哪个信号
对这个输出信号产生了影响
所以我们可以用增加驱动信号的方式
这个按钮
然后让软件自动的把对这个信号
有影响的信号添加到波形窗口里面来
这样
我们就可以只观测我们所关注的信号
提高我们的仿真的效率
如果设计的结果能够符合我们的预期
快速的找到问题所在
这样一个仿真过程就完了
但通常来说
我们做的设计
是需要花很长时间去找出问题的
也就是通常来说
我们所写完的代码
很少能够一次成功
通常我们的代码会有种种的错误
各种各样的错误
我们作为设计人员
要做的事情就要去定位
找出这样的错误
怎么找呢
最直观的方法就是刚才所说的
在波形窗口里面去找
但有时候波形窗口去找也是很难的
需要用一些高层次的分析方法
去定位这个错误
比较有用的一种方法
就是在数据流窗口里面去进行调试
去追踪信号的来源
举个例子
以我们这个设计为例
我们可以在数据流窗口里面
显示出我们这个设计的层次图
我们选择count信号
就可以让软件把count信号
产生的相应的流图画出来
比如说有一个always进程
这个always进程
有reset和clk这两个输入信号
产生了count
我们选择了reset信号
选中reset信号以后
又可以用这几个按钮
例如中间这个按钮显示出跟reset信号
相连的所有的进程和所有的实体
这样我们就可以把跟reset相连的
所有电路都能够画出来
画出来连接图
根据这个连接图
我们就可以分析
当reset信号有故障的时候
它到底是由谁来产生的故障
或者说reset信号
它的后续电路都有什么电路
比如initial这个进程
它产生了一个reset
都有哪些进程会受这个进程的影响
这样我们就知道
万一这个进程有问题
哪些进程会出错
便于我们去找到问题所在
另外在波形窗口里面
我们通常会把这个Dataflow调试工具
跟波形窗口以及源代码进行交叉定位
方便我们快速找到问题所在
例如我们在这个进程里面
发现count的计数值出错了
这个出错(的原因)
一个电路的输出发生了错误
那一定是由于它的输入
跟我们的预期不一致
或者说本身的行为有问题才会导致(出错)
对吧
所以在这种情况下
我们要观测这个进程
它都有哪些输入信号
以及这些输入信号都处于什么值
用这种方式我们就可以定位
reset跟它相关的是什么进程
然后检查这个进程的输出信号
是不是一致
我们在看always进程的时候
有可能我们已经忘了
当时怎么写的进程了
如果你的设计有几千行 几万行
不可能记住这个always进程到底干了什么
这样我们双击这个always进程
软件就会自动的把always进程
所对应的源代码窗口打开
并且定位到这个进程上
我们就可以去进一步检查
这个进程的内部细节
通过这种方式
我们就可以快速的找到问题所在
问题所在的进程
以及到底是什么样的数据变化
产生出了错误的数据输出
这就是我们软件调试的常见的方法
-软件下载说明
-a) 集成电路的应用及市场
-a) 集成电路的应用及市场--作业
-b)集成电路的制造过程
-b)集成电路的制造过程--作业
-c)从CPU的发展看IC的进展
-c)从CPU的发展看IC的进展--作业
-d)从行业的发展看IC的进展
--Video
-d)从行业的发展看IC的进展--作业
-e)从ISSCC看IC的发展方向
--讲课视频
-e)从ISSCC看IC的发展方向--作业
-a)数字系统的实现方法 (ASSP/FPGA/ASIC的对比)
--讲课视频
-a)数字系统的实现方法 (ASSP/FPGA/ASIC的对比)
-b)组合逻辑电路
--Video
-2、数字集成电路设计方法--b)组合逻辑电路
-c)时序逻辑电路(1)
-d)时序逻辑电路(2)
-2、数字集成电路设计方法--d)时序逻辑电路(2)
-a)Verilog的历史和学习要点
--讲课视频
-b)端口、信号及数据类型
--讲课视频
-b)端口、信号及数据类型--作业
-c)逻辑电平及数据操作
--讲课视频
-3、Verilog语法--c)逻辑电平及数据操作
-d)Assign 语句
-e)Assign 举例
-f)Always
-f)Always--作业
-g)阻塞与非阻塞赋值
--Video
-3、Verilog语法--g)阻塞与非阻塞赋值
-h)D触发器的描述
--Video
-i)时序电路的设计
--Video
-i)时序电路的设计--作业
-j) 面向测试的Verilog语法(1)
-k) 面向测试的Verilog语法(2)
-k) 面向测试的Verilog语法(2)--作业
-a)电路设计实例1
--Video
-b)电路设计实例2
--讲课视频
-b)电路设计实例2--作业
-c)电路设计实例3
--讲课视频
-Modelsim仿真
-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)--作业