当前位置: 代码迷 >> 综合 >> FPGA之道(83)功能仿真之仿真语法(Graphic Waveform )
  详细解决方案

FPGA之道(83)功能仿真之仿真语法(Graphic Waveform )

热度:17   发布时间:2023-12-12 19:56:02.0

文章目录

  • 前言
  • 仿真语法
    • Graphic Waveform
      • 数字波形简介
      • 从实际到仿真
        • 实际系统检测
        • 软件仿真模拟
      • “Hello world”之Graphic Waveform
        • 待仿真设计
      • 一些绘制波形的操作
        • 添加端口
        • 创建时钟信号
        • 钳制与释放信号
        • 电平翻转
        • 生成随机序列
        • 总线设置
      • 一些观察波形的操作
        • 波形缩放
        • 总线观察
        • 添加时标
        • 边沿寻找
      • 波形仿真结果分析及重要注意事项
        • 一、如果判断仿真结果对与错?
        • 二、仿真0时刻的意义。
        • 三、“边沿对边沿”的判定。

前言

本文摘自《FPGA之道》。

仿真语法

本章节将为大家介绍几类常用的仿真编程语法,包括图形化仿真、VHDL、Verilog、System Verilog以及Assertion。其中,图形化仿真是最原始的一种仿真方法,在这里介绍的目的是为了让大家对仿真有一个初步了解;VHDL与Verilog除了用于FPGA设计的描述外,也可以用来进行仿真代码的编写,由于从事FPGA项目的工作人员一般都具有较好的HDL语言基础,因此这两者在仿真方面的使用还是比较广泛的;而System Verilog则是更为强大、更加专业的仿真语法,这也是本章节介绍的重点;对于Assertion,与其说它是一种仿真的语法,不如说它是一种进阶的仿真方法或者其它仿真语法的一个子部分,因为通常来说它需要结合VHDL、Verilog或者System Verilog来使用,不过System Verilog对其的支持是最全面、最好的。
FPGA仿真语法与FPGA设计语法最本质的区别就在于用其所编写的代码是否需要对应于具体的数字电路。所以凡是FPGA仿真语法都是软件设计语言,凡是FPGA设计语法都是硬件描述语言,关于这两者区别的详细阐述可以参阅【共同语言篇->硬件描述语言->软件编程思路与FPGA编程思路的变革】章节。因此,在学习仿真语法时,需要转换一下思路,更多的以软件的视角去审视问题,以防落入【程序设计篇】中的思维定式,制约了我们的发挥。
由于FPGA仿真语法其实是软件的编程语法,因此其在编写的时候更加的随意、更加的灵活。所以,为了能够让大家比较容易的入门,本章节采用“入门范例+语法介绍”的模式。其中入门范例环节都统一以“Hello World”命名,这是因为“Hello World”在所有编程语言的起始阶段,占据着无法撼动的历史地位,几乎在所有国家的所有版本的编程教材中,“Hello World”总是作为第一个程序测试范例记录于书本之中,几乎所有编程的第一步就在于此了,所以它是经典之中的经典!因此本章节入门范例环节的范例虽然并不一定输出“Hello World”关键字,但其对于我们入门仿真语法的重要性与“Hello World”是一样的,因此将这些小节统一用“Hello World”命名,以表示对这一经典的深深敬意!
最后请注意,FPGA的仿真语法也是支持混合编程的,不过除非万不得已,尽量不要给自己找麻烦。接下来,我们就开始逐个介绍这些FPGA仿真语言的语法。

Graphic Waveform

Graphic Waveform方法对于功能仿真来说是入门级中的入门,不过在本小节中介绍的一些基本概念和注意事项却是非常非常重要的,请务必认真阅读。

数字波形简介

数字波形就是逻辑电平对时间的图形表示形式。
首先,逻辑电平的取值是离散的,例如:对于四值逻辑电平来说,0V电压表示逻辑0,1V电压表示逻辑1,2V电压表示逻辑2,3V电压表示逻辑3;对于三值逻辑电平,-1V电压表示逻辑-1,0V电压表示逻辑0,1V电压表示逻辑1;等等。不过在实际中应用最广泛的还是二值逻辑电平,例如:TTL3V3,0V表示逻辑0,3.3V表示逻辑1;LVCMOS1V8,0V表示逻辑0,1.8V表示逻辑1;LVDS2V5,差分线间压差为350mV表示逻辑1,压差为-350mV表示逻辑0;等等。二值逻辑电平虽然每一次传输的信息量比较少,但是其抗噪声性能却最强,并且传输速率也可以很快,而且也是物理最容易实现的。如果需要同时传输更多的信息量,也可以利用多根信号线来组成2的N次方种变化以适应要求。所以在我们的FPGA设计中,使用的就是这种二值逻辑电平。为了统一起见,在进行数字波形绘制过程中,逻辑电平的幅度值我们统一用逻辑1、逻辑0来表示,而不去计较其所对应的实际物理电平是多少。
其次,请注意,虽然数字信号在幅度上是离散的,但是其在时间上却是连续的,因为电信号在实际中都是连续的。
由于逻辑电平的取值范围是有限的且离散的,而时间的取值范围是无限的且连续的,因此在数字波形的绘制中,我们用横坐标表示时间,纵坐标表示逻辑电平的幅度。以下是一些二值数字波形的示例,供大家参考:
示例一:clockA、clockB、clockC周期均为10ns,占空比分别为40%、50%、60%。
在这里插入图片描述
示例二:某一个分辨率为1920x1080视频信号的行、场扫描及数据使能信号的传输波形。
在这里插入图片描述

从实际到仿真

实际系统检测

我们先来看一看数字电路在现实世界中的工作情况吧。
如下图所示,电路中的FPGA芯片实现的是一个逻辑与的功能,
在这里插入图片描述
在电路正常工作的情况下,我们可以用示波器A、B、C分别观察其两个输入引脚和一个输出引脚,得到的波形图可能如下:
在这里插入图片描述
通过上图,我们可以大致判断出该FPGA芯片的行为符合预期,因此可以算是基本完成了该芯片的验证工作。注意,由于实际电路中存在着时间延迟,因此示波器C中的波形要比A、B滞后一些,而在功能仿真中是不需要考虑任何时间延迟信息的。

软件仿真模拟

什么是仿真?仿真就是对真实系统的模拟,在计算机技术应用日趋广泛的今天,仿真基本上都是通过计算机来完成。通过上一小节的介绍,我们可以看出,要想仿真该FPGA设计,最简单的思路就要想办法在计算机上模拟产生出示波器A、B中所示的波形图,模拟出FPGA芯片的与逻辑功能,最后再模拟出示波器A、B、C的接收功能,用来绘制输入、输出信号的波形图并进行结果分析。
以上三个需要模拟的要素中,FPGA设计的功能代码其实就是对FPGA芯片功能最好的一个模拟,而仿真器本身就可以模拟示波器的波形观察功能,因此,问题的焦点就集中到如何在计算机上产生形如示波器A、B中所呈现的激励波形上。当然了,解决方法有很多种,你可以使用但不限于【本篇->仿真语法】章节中的任何一种语法,不过最直接也最原始的方法就是手动绘制波形激励。接下来将针对Graphic Waveform进行一些基本介绍。

“Hello world”之Graphic Waveform

待仿真设计
待仿真设计的数字电路原理图如下:

在这里插入图片描述

仿真示例
采用Graphic Waveform方法对FPGA设计进行仿真时,其仿真波形的输入一般都是工具相关的,因为不同的仿真工具提供不同的波形格式、绘制方法和仿真界面。不过大体的步骤如下:
1、前期准备工作;
2、在波形中添加输入端口和待观察的输出端口;
3、绘制输入激励波形图,针对本例如下:
在这里插入图片描述
4、观察输出端口的波形,并据此进行本次仿真分析,针对本例如下:
在这里插入图片描述
可以看出,在第二个时钟上升沿之前,输出为不定态,这是因为此时寄存器A、B中的数据并不确定(可以通过在代码中赋初值的形式来去掉不定态),不过在此之后,输出波形结果与预期相符。

一些绘制波形的操作

本小节介绍一些基本的波形图绘制的操作,供大家参考:

添加端口

添加端口是波形图绘制的第一步,因为没有输入端口,那么就没有被绘制的对象,而没有输出端口,就没有仿真结果的显示对象。不过与实际中的电路测试不同,仿真的时候也可以将任意FPGA设计或者仿真代码中的一些中间信号添加到波形图中进行观察,这也是仿真相对于实测的另一优势。

创建时钟信号

除了纯组合逻辑外,通常FPGA设计都是针对时序逻辑的,因此时钟信号在整个设计中占据了十分重要的地位。由于时钟信号具有周期性、无限性,因此其绘制工作也是非常具有重复性的,所以通常我们不直接手动绘制时钟信号,而是通过一些简单设置来在波形图上生成一个符合我们要求的时钟信号。

钳制与释放信号

对于数据信号来说,除了手动绘制外,通常用钳制和释放的方法来精确控制。钳制和释放也是通过简单设定来实现的,例如,在100ns时刻,钳制信号a为逻辑1,在200ns后释放对信号的钳制,这样,在100ns时刻以前和200ns时刻以后,就可以对信号进行不同的设置。

电平翻转

此选项一般用于后期对仿真波形的修改,它可以对选中区域的波形图进行电平翻转,即逻辑1变为逻辑0,逻辑0变为逻辑1。除此以外,有一个小技巧,就是在一开始令某一个输入端口的波形图全部为逻辑0或逻辑1,这样就可以利用电平翻转操作来迅速的绘制出想要的波形激励。

生成随机序列

有的时候,我们需要一些比较随机的仿真激励波形,这时,手动绘制往往工作量过大,此时,可以利用生成随机序列的功能选项,经过简单设置产生一些不规则的仿真激励波形。

总线设置

有些时候,输入信号是多位的,例如两个8bits位宽的数据A和B相加。这个时候,在绘制波形图时,如果针对A、B共16根输入线分别进行波形绘制,则会非常的麻烦,因此,仿真器一般会将多位数据信号看做总线,此时,我们可以分别对总线A、B进行统一的绘制操作,其效果将会非常的直观。例如下图,通过直接为总线A、B设置8位2进制数值,就相当于针对每一根数据线进行相应的波形绘制。

在这里插入图片描述
除以上介绍的几点外,关于波形绘制的操作还有很多,大家可以在实际的使用中慢慢研究,这里不再赘述。

一些观察波形的操作

本小节介绍一些基本的波形观察操作,供大家参考:

波形缩放

波形缩放应该算是观察波形时最为常用的一类操作了,由于计算机显示屏尺寸的限制,以及计算机内存的限制,对于仿真时间比较长的波形图,计算机肯定无法同时将所有细节都显示出来,这时候,就需要用到波形缩放操作,这类似于我们用计算机看Google地图时的缩放操作。

总线观察

通常情况下,总线默认都是以2进制数的形式来表示的,如【一些绘制波形的操作】小节中最后的例子所示。除此以外,为了进一步方便我们观察波形,我们还可以令总线的显示形式为八进制、十六进制、十进制等等,并且还可根据需要令其显示为有符号数或者无符号数。例如该例也可表示为:
在这里插入图片描述

添加时标

时标就是在波形图上添加一条竖直的坐标线,函数表达式为t=D,其中D为某一常数。时标是进行波形图观察时一种很好的辅助方式,通过引入多个时标还可以用来进行脉冲测量等操作,例如:

在这里插入图片描述

边沿寻找

数字波形的变化处往往是我们最关心的位置,因此观察波形时,一类常用的操作就是边沿查找,其中以跳转至下一边沿和跳转至上一边沿两种操作最为常用。注意,对于总线类型的数据来说,边沿指的就是数据变化的位置。

除以上介绍的几点外,关于波形观察的操作还有很多,大家可以在实际的使用中慢慢研究,这里不再赘述。

波形仿真结果分析及重要注意事项

在分析仿真结果时,有一些需要特别注意的地方,在这里为大家做一些基本的介绍。请注意,本小节的内容不光适用于Graphic Waveform方法,对于其它语法形式都适用。

一、如果判断仿真结果对与错?

有两种方法。第一种,用眼睛看。这是最常用的一种方法,由于我们对输出波形的格式有预期,因此我们可以直接观察仿真结果来判断被仿真FPGA设计行为的正确性。第二种,波形比较,这种方法更加高级一些,我们可以先绘制出预期的仿真结果波形,然后将该波形与仿真结果波形进行对比,两者不一致的地方会以红色或者高亮显示,这样更方便我们找到出问题的地方。

二、仿真0时刻的意义。

什么是仿真的0时刻?一般来说,默认仿真最开始的时刻就是仿真0时刻,也就是当你点击开始仿真按钮的那一瞬间,仿真0时刻纪元开始。请注意,仿真0时刻是一个相对值,而不是一个绝对的值,这类似于电压中0电势的定义,重要的不是认定什么时候才是0时刻,而是需要确定这么一个时刻,好让所有其它的时刻都可以此时刻为基准,来进行描述。通常来说,这个被确定的时刻称为0时刻,当然了,你也可以称之为1时刻、-1时刻甚至N时刻,不过称之为0时刻更有利于我们对一些时间概念的表述和理解。这就好比你非要规定0摄氏度是水烧开的温度,那么在此参照系下,-100摄氏度对应冰水混合物的温度,这并没有什么错误,只不过与我们通常所接触到的概念有所出入,因此理解起来会困难许多。

三、“边沿对边沿”的判定。

对于时序逻辑的仿真来说,当出现时钟信号的有效边沿时(一般是上升沿),对应的数据信号的逻辑电平会被传递到寄存器的输出端,例如“Hello world”小节中的绘制的波形激励,时钟信号与数据信号是一种“边沿对电平”的关系,因此对于寄存器A的行为模拟我们没有任何异议。可是,如果时钟信号的有效边沿正好也对应到了数据信号的边沿,由于无法说清楚数据信号此时到底是逻辑1还是逻辑0,寄存器传递的信号情况又该是怎样呢?对于功能仿真来说,给出如下通解:
如果时钟边沿发生在t时刻,那么令Δ为正无穷小,则被寄存器传递的数据逻辑电平所处的时刻为t-Δ时刻。对于时钟有效边沿与数据信号的四种对应关系列举如下:
1、时钟有效边沿对应数据逻辑1电平,则t-Δ时刻的数据线上仍为逻辑1电平,这种情况下寄存器输出逻辑1电平至其输出端;
2、时钟有效边沿对应数据逻辑0电平,则t-Δ时刻的数据线上仍为逻辑0电平,这种情况下寄存器输出逻辑0电平至其输出端;
3、时钟有效边沿正好对齐数据线上从逻辑1到逻辑0电平的跳变,则t-Δ时刻的数据线上应该为逻辑1电平,这种情况下寄存器输出逻辑1电平至其输出端;
4、时钟有效边沿正好对齐数据线上从逻辑0到逻辑1电平的跳变,则t-Δ时刻的数据线上应该为逻辑0电平,这种情况下寄存器输出逻辑0电平至其输出端;
如果大家注意观察,其实“Hello world”小节中寄存器B的输入端碰到的就是“边沿对边沿”的情况,通过观察其输入、输出端口的仿真波形,我们看到其结果符合上述通解。
在这里插入图片描述
上述四个标出的位置从左到右分别对应于通解中的关系3、2、4、1。
事实上,我们正是从移位寄存器所应具有的行为上得出了功能仿真时寄存器的通解,但是请注意,现实中的原因往往这样的:如果时钟边沿发生在t时刻,那么令Δ为较小的正延迟时间参数(一般相对于时钟周期来说较小),则寄存器A输出更新的时刻为t+Δ时刻,在不考虑时钟路径延迟的情况下,寄存器B的时钟有效边沿时刻为t时刻,对应的数据逻辑电平其实还是寄存器A在t时刻输出的逻辑电平,因此数据才能在移位寄存器中逐个传递下去。
可是由于功能仿真中不考虑延迟,所以寄存器A输出的更新时刻仍为t时刻,因此在这个时候,为了确定寄存器B的输出,就必须追朔到t-Δ时刻。
最后,请注意,功能仿真中可以出现“边沿对边沿”的情况,因为功能仿真不考虑时间延迟参数,只是从原理上来验证FPGA设计,但是在时序仿真中,“边沿对边沿”的情况一般都是会有时序问题的,甚至两个边沿离得太近都会导致设计行为发生错误。因此功能仿真中的出现“边沿对边沿”情况与实际电路出现“边沿对边沿”的情况之间没有任何必然联系,所以不必担心它会导致寄存器的建立时间或保持时间余量不满足。我见过有些人,因为在功能仿真的时候发现了“边沿对边沿”的情况就想当然的联想到了一知半解的时序概念,于是就赶紧对寄存器B的时钟做个反向,从而求得心理上的极大安慰与满足,殊不知这样做的效果往往适得其反,是非常不可取的。