当前位置:首页 > > ZYNQ


文章目录

  1. 前言

  2. 测试模块设计

  3. 仿真全过程
    模块包含
    定义顶层模块
    元件例化
    测试激励的书写
    波形仿真
    系统任务仿真

  4. 总结

01. 前言

在FPGA 高手养成记-Test bench文件结构一览无余 只是简单的例举了常用的 testbench 写法,在工程应用中基本能够满足我们需求, 至于其他更为复杂的 testbench 写法, 大家可参考其他书籍或资料。

testbench没有像RTL代码设计那样严谨,我们可以在符合语法规则的前提下,随意编写我们的测试文件,有些在RTL代码中不可综合的语句,我们可以在testbench中实现。大体流程如下:

02. 测试模块设计

要测试我们的cpu需要ROM和RAM模块,这就需要我们先做好这两个模块

这里定义了一个 1024 x 8 的RAM

再定义一个8192  x 8 的ROM

ROM和RAM都还没有装入数据,等会我们会调用函数给他们装数据,接下来是地址译码器,来控制ROM和RAM的打开与关闭。

各模块建立好之后我们就开始仿真了。

03.仿真

这次教学我们用的是modelsim SE 10.0 版本进行教学,直接先在quartus II中建一个.v文件将其保存在原来的工程文件目录中,并命名为cpu_top.v,直接在这里写测试代码

下面大家可以来完成cpu 的仿真过程了

3.1,模块包含

首先,我们需要将我们刚写好的那几个模块包含进去,即CPU模块,ROM模块,RAM模块,地址译码器模块,并写好时间测量度,见下图

3.2,定义顶层模块

由于我们的设计只有两个输入,即时钟模块和复位模块,凡是输入信号在testbench中统一定义成reg型变量,凡是输出或者双向输入输出信号统一定义成wire型变量,我们的设计只有输入没有输出,故只定义输入和连线即可

下图便是我们要组成的测试顶层模块图,我们定义的wire型变量,实际就是我们顶层模块中,模块模块与模块间的连线。而这些连线就是我们cpu的输出,这样我们就可以用我们的测试模块来测试我们的cpu是否能正确工作

3.3. 元件例化

就是将各个模块连接起来即可,这里就不做太多的说明了,因为以前都写过很多次了

3.4.测试激励的书写

先写好时钟产生模块和复位模块.并将复位模块用task任务封装,这样我们在测试过程中就可以随时调用复位任务进行复位

时钟为50Mhz,复位时间为20ns

然后,我们再用task封装我们需要的模块,我们来想一下,上电后,CPU会从ROM中读两个时钟周期的数据是吧,但是我们的ROM现在还是空的,所以我们需要一个任务是往ROM中装入程序,给ROM中装数据我们可以用系统函数$readmemb,即打开一个文件,并将其中的数据送到我们之前定义的ROM中去

而test1.pro文件是需要我们自己定义的,我们可以在quartusII中再新建一个.v文件,在里面写上我们自己定义的程序,并将其保存为.pro文件即可,至于写什么程序,是我们随便定义的.

装完ROM和RAM的数据之后,按说就可以了进行波形仿真了,因为cpu是自动读取数据的,下面我们先来做第一步仿真,我先把之后的代码注释掉,大家先看没有被注释掉的代码

里面都是我们之前封装好的函数,刚开始进行复位,然后进行第一步测试,之后停止,将其保存之后,并默认为用其打开,打开后见下图

然后,file——new——library——ok即建好一个库

点击左上角的编译按钮,将我们之前写好的所有.v文件全部都编译进去

看到transcript一栏显示编译成功后即可,若没有transcript一栏,可以选择菜单中的view——transcript即可,若显示有红色错误,那就请读者按照它的要求进行修改代码,这说明你的代码有问题,一般是连接问题

3.5,波形仿真

编译成功后,双击cpu_top就可以开始波形仿真了

进入仿真页面后,我们右击cpu模块将其加入至波形

大家先看两个图,等会结合这两个图给大家细细讲解仿真过程

我们先来看第一个过程

上电后,cpu先从ROM中读回两个周期的数据,是从ROM的0地址开始的,再对比我们之前定义好的ROM,数据读取正确,读回的数据的前三位是111,即指令码JMP,后13位003c为地址码,JMP指令是将读回的数据作为新的地址码来读取相应地址的数据。那么,下一步,cpu应该是从ROM的003c地址处读数据才对,再看一下波形

对比波形后可知,cpu正好是从003c处读取数据,读到的数据指令码位111即JMP,地址码位0006,再到ROM的0006地址处看

这次读回的指令码位101,即LDA,也就是说将后13位地址码对应的RAM中的数据读回,送到累加器中,想一下,这时的RAM应该是打开的,而且双向输入输出口的数据总线上应该是来自RAM的8位数据,由于ROM0006地址处的地址码为1800是13位的,而RAM的地址是9位的,因此实际上我们从RAM中读回的数据是从RAM的0地址读回的,即我们之前给RAM写好的0000_0000,再看一下波形

正如我们所想的一样,数据总线上是0000_0000,RAM是打开的,地址为1800

就这样,读者可以自己再试一下,看看我们的cpu是不是按照我们之前给他的程序运行的,在这里我就不再给大家一一介绍了

虽然波形仿真很直观,但是看久了就会令人眼花缭乱,尤其是数据很多的时候,我们只能看其中一部分,不能讲所有数据看完整,这时候我们单单是用波形来仿真就远远不够了,下面介绍用系统任务仿真的过程

3.6,系统任务仿真

再回到我们的代码,注释掉了一些代码吧,我们把那些代码给加上,以其中一个过程为例

假设读回的指令码位101,即LDA,如果我在fentch_8的高电平期间且在cpu输出地址为奇数的时候记录一下此时的时间、指令、地址、目的地址、数据的话就可以不用看波形,让电脑来帮助我们来分析了,因此作如下处理

这里我延时60ns,是因为第一次记录的时候数据总线上还没有数据,只有延时一会才会有数据,即上面那张波形图右边那根黄色的线处记录一下数据,并将其显示。我们也可以加上一下标注,来帮助我们观察

这样我们再来仿真的时候就不用看波形了,直接打开transcript一栏观察记录即可

这样便可以为我们省下大量的仿真时间

04. 总结

这里提出以下几点建议供大家参考:

  • 封装有用且常用的 testbench, testbench 中可以使用 task 或 function 对代码进行封装, 下次利用时灵活调用即可;

  • 如果待测试文件中存在双向信号(inout)需要注意, 需要一个 reg 变量来表示输入, 一个 wire 变量表示输出;

  • 单个 initial 语句不要太复杂,可分开写成多个 initial 语句, 便于阅读和修改;

  • Testbench 说到底是依赖 PC 软件平台, 必须与自身设计的硬件功能相搭配。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
关闭