【Verilog 教程】6.6Verilog 仿真激励

关键词:testbench,仿真,文件读写
Verilog 代码设计完成后,还需要进行重要的步骤,即逻辑功能仿真。仿真激励文件称之为 testbench,放在各设计模块的顶层,以便对模块进行系统性的例化调用进行仿真。

毫不夸张的说,对于稍微复杂的 Verilog 设计,如果不进行仿真,即便是经验丰富的老手,99.9999% 以上的设计都不会正常的工作。不能说仿真比设计更加的重要,但是一般来说,仿真花费的时间会比设计花费的时间要多。有时候,考虑到各种应用场景,testbench 的编写也会比 Verilog 设计更加的复杂。所以,数字电路行业会具体划分设计工程师和验证工程师。

下面,对 testbench 做一个简单的学习。

testbench 结构划分
testbench 一般结构如下:

在这里插入图片描述
其实 testbench 最基本的结构包括信号声明、激励和模块例化。

根据设计的复杂度,需要引入时钟和复位部分。当然更为复杂的设计,激励部分也会更加复杂。根据自己的验证需求,选择是否需要自校验和停止仿真部分。

当然,复位和时钟产生部分,也可以看做激励,所以它们都可以在一个语句块中实现。也可以拿自校验的结果,作为结束仿真的条件。

实际仿真时,可以根据自己的个人习惯来编写 testbench,这里只是做一份个人的总结。

testbench 仿真举例
前面的章节中,已经写过很多的 testbench。其实它们的结构也都大致相同。

下面,我们举一个数据拼接的简单例子,对 testbench 再做一个具体的分析。

一个 2bit 数据拼接成 8bit 数据的功能模块描述如下:

实例

module  data_consolidation(input           clk ,input           rstn ,input [1:0]     din ,          //data ininput           din_en ,output [7:0]    dout ,output          dout_en        //data out);// data shift and counterreg [7:0]            data_r ;reg [1:0]            state_cnt ;always @(posedge clk or negedge rstn) beginif (!rstn) beginstate_cnt     <= 'b0 ;data_r        <= 'b0 ;endelse if (din_en) beginstate_cnt     <= state_cnt + 1'b1 ;    //数据计数data_r        <= {data_r[5:0], din} ;  //数据拼接endelse beginstate_cnt <= 'b0 ;endendassign dout          = data_r ;// data output enreg                  dout_en_r ;always @(posedge clk or negedge rstn) beginif (!rstn) begindout_en_r       <= 'b0 ;end//计数为 3 且第 4 个数据输入时,同步输出数据输出使能信号else if (state_cnt == 2'd3 & din_en) begin  dout_en_r       <= 1'b1 ;endelse begindout_en_r       <= 1'b0 ;endend//这里不直接声明dout_en为reg变量,而是用相关寄存器对其进行assign赋值assign dout_en       = dout_en_r;endmodule

对应的 testbench 描述如下,增加了文件读写的语句:

实例

`timescale 1ns/1ps//============== (1) ==================//signals declaration
module test ;reg          clk;reg          rstn ;reg [1:0]    din ;reg          din_en ;wire [7:0]   dout ;wire         dout_en ;//============== (2) ==================//clock generatingreal         CYCLE_200MHz = 5 ; //always beginclk = 0 ; #(CYCLE_200MHz/2) ;clk = 1 ; #(CYCLE_200MHz/2) ;end//============== (3) ==================//reset generatinginitial beginrstn      = 1'b0 ;#8 rstn      = 1'b1 ;end//============== (4) ==================//motivationint          fd_rd ;reg [7:0]    data_in_temp ;  //for self checkreg [15:0]   read_temp ;     //8bit ascii data, 8bit \ninitial begindin_en    = 1'b0 ;        //(4.1)din       = 'b0 ;open_file("../tb/data_in.dat", "r", fd_rd); //(4.2)wait (rstn) ;    //(4.3)# CYCLE_200MHz ;//read data from filewhile (! $feof(fd_rd) ) begin  //(4.4)@(negedge clk) ;$fread(read_temp, fd_rd);din    = read_temp[9:8] ;data_in_temp = {data_in_temp[5:0], din} ;din_en = 1'b1 ;end//stop data@(posedge clk) ;  //(4.5)#2 din_en = 1'b0 ;end//open tasktask open_file;input string      file_dir_name ;input string      rw ;output int        fd ;fd = $fopen(file_dir_name, rw);if (! fd) begin$display("--- iii --- Failed to open file: %s", file_dir_name);endelse begin$display("--- iii --- %s has been opened successfully.", file_dir_name);endendtask//============== (5) ==================//module instantiationdata_consolidation    u_data_process(.clk              (clk),.rstn             (rstn),.din              (din),.din_en           (din_en),.dout             (dout),.dout_en          (dout_en));//============== (6) ==================//auto checkreg  [7:0]           err_cnt ;int                  fd_wr ;initial beginerr_cnt   = 'b0 ;open_file("../tb/data_out.dat", "w", fd_wr);forever begin@(negedge clk) ;if (dout_en) begin$fdisplay(fd_wr, "%h", dout);endendendalways @(posedge clk) begin#1 ;if (dout_en) beginif (data_in_temp != dout) beginerr_cnt = err_cnt + 1'b1 ;endendend//============== (7) ==================//simulation finishalways begin#100;if ($time >= 10000)  beginif (!err_cnt) begin$display("-------------------------------------");$display("Data process is OK!!!");$display("-------------------------------------");endelse begin$display("-------------------------------------");$display("Error occurs in data process!!!");$display("-------------------------------------");end#1 ;$finish ;endendendmodule // test

仿真结果如下。由图可知,数据整合功能的设计符合要求:加粗样式
在这里插入图片描述
testbench 具体分析
1)信号声明

testbench 模块声明时,一般不需要声明端口。因为激励信号一般都在 testbench 模块内部,没有外部信号。

声明的变量应该能全部对应被测试模块的端口。当然,变量不一定要与被测试模块端口名字一样。但是被测试模块输入端对应的变量应该声明为 reg 型,如 clk,rstn 等,输出端对应的变量应该声明为 wire 型,如 dout,dout_en。

2)时钟生成

生成时钟的方式有很多种,例如以下两种生成方式也可以借鉴。

实例

initial clk = 0 ;
always #(CYCLE_200MHz/2) clk = ~clk;initial beginclk = 0 ;forever begin#(CYCLE_200MHz/2) clk = ~clk;end
end      

需要注意的是,利用取反方法产生时钟时,一定要给 clk 寄存器赋初值。

利用参数的方法去指定时间延迟时,如果延时参数为浮点数,该参数不要声明为 parameter 类型。例如实例中变量 CYCLE_200MHz 的值为 2.5。如果其变量类型为 parameter,最后生成的时钟周期很可能就是 4ns。当然,timescale 的精度也需要提高,单位和精度不能一样,否则小数部分的时间延迟赋值也将不起作用。

3)复位生成

复位逻辑比较简单,一般赋初值为 0,再经过一段小延迟后,复位为 1 即可。

这里大多数的仿真都是用的低有效复位。

4)激励部分

激励部分该产生怎样的输入信号,是根据被测模块的需要来设计的。

本次实例中:

(4.1) 对被测模块的输入信号进行一个初始化,防止不确定值 X 的出现。激励数据的产生,我们需要从数据文件内读入。
(4.2) 处利用一个 task 去打开一个文件,只要指定文件存在,就可以得到一个不为 0 的句柄信号 fp_rd。fp_rd 指定了文件数据的起始地址。
(4.3) 的操作是为了等待复位后,系统有一个安全稳定的可测试状态。
(4.4) 开始循环读数据、给激励。在时钟下降沿送出数据,是为了被测试模块能更好的在上升沿采样数据。
利用系统任务 $fread ,通过句柄信号 fd_rd 将读取的 16bit 数据变量送入到 read_temp 缓存。

输入数据文件前几个数据截图如下。因为 $fread 只能读取 2 进制文件,所以输入文件的第一行对应的 ASCII 码应该是 330a,所以我们想要得到文件里的数据 3,应该取变量 read_temp 的第 9 到第 8bit 位的数据。
在这里插入图片描述
信号 data_in_temp 是对输入数据信号的一个紧随的整合,后面校验模块会以此为参考,来判断仿真是否正常,模块设计是否正确。

(4.5) 选择在时钟上升沿延迟 2 个周期后停止输入数据,是为了被测试模块能够正常的采样到最后一个数据使能信号,并对数据进行正常的整合。
当数据量相对较少时,可以利用 Verilog 中的系统任务 $readmemh 来按行直接读取 16 进制数据。保持文件 data_in.dat 内数据和格式不变,则该激励部分可以描述为:

实例

reg [1:0] data_mem [39:0] ;
reg [7:0] data_in_temp ; //for self check
integer k1 ;
initial begin
din_en = 1’b0 ;
din = 'b0 ;
$readmemh(“…/tb/data_in.dat”, data_mem);
wait (rstn) ;
# CYCLE_200MHz ;

//read data from file
for(k1=0; k1<40; k1=k1+1)  begin@(negedge clk) ;din    = data_mem[k1] ;data_in_temp = {data_in_temp[5:0], din} ;din_en = 1'b1 ;
end//stop data
@(posedge clk) ;
#2 din_en = 1'b0 ;

end

5)模块例化

这里利用 testbench 开始声明的信号变量,对被测试模块进行例化连接。

6)自校验

如果设计比较简单,完全可以通过输入、输出信号的波形来确定设计是否正确,此部分完全可以删除。如果数据很多,有时候拿肉眼观察并不能对设计的正确性进行一个有效判定。此时加入一个自校验模块,会大大增加仿真的效率。

实例中,我们会在数据输出使能 dout_en 有效时,对输出数据 dout 与参考数据 read_temp(激励部分产生)做一个对比,并将对比结果置于信号 err_cnt 中。最后就可以通过观察 err_cnt 信号是否为 0 来直观的对设计的正确性进行判断。

当然如实例中所示,我们也可以将数据写入到对应文件中,利用其他方式做对比。

7)结束仿真

如果我们不加入结束仿真部分,仿真就会无限制的运行下去,波形太长有时候并不方便分析。Verilog 中提供了系统任务 $finish 来停止仿真。

停止仿真之前,可以将自校验的结果,通过系统任务 $display 在终端进行显示。

文件读写选项
用于打开文件的系统任务 $fopen 格式如下:

fd = $fopen("<name_of_file>", "mode")

和 C 语言类似,打开方式的选项 “mode” 意义如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/94151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

word已排序好的参考文献,插入新的参考文献,序号更新

原排序好的文献序号。 现在在3号后面插入一个新文献。4&#xff0c;5号应该成为5&#xff0c;6 这时在3号后面&#xff0c;回车&#xff0c;就会自动的增长。如下图&#xff1a; 但是如果手滑&#xff0c;把[4]删除了如何排序&#xff1f;&#xff1f; 如下图&#xff1a; …

怎么将本地代码文件夹通过Git 命令上传到启智平台仓库

在本地创建一个与启智平台仓库同样名字的文件夹 然后在本地文件夹右键–>选择Git Bash Here,就会打开Git命令窗口 初始化本地仓库 git init将项目文件添加到Git git add .提交更改&#xff1a; 使用以下命令提交您的更改&#xff0c;并为提交添加一条描述性的消息&#…

创建线程池

如何创建线程池及处理相应任务 目录 如何创建线程池及处理相应任务线程池定义解决的问题(需求)工作原理实现线程池创建示意图重要构造器创建线程池(ExecutorService)线程池任务处理常用API处理Runnable任务处理Callable任务 使用工具类(Executors)创建线程池常用API应用案例 拓…

极大似然估计概念的理解——统计学习方法

目录 1.最大似然估计的概念的理解1 2.最大似然估计的概念的理解2 3.最大似然估计的概念的理解3 4.例子 1.最大似然估计的概念的理解1 最大似然估计是一种概率论在统计学上的概念&#xff0c;是参数估计的一种方法。给定观测数据来评估模型参数。也就是模型已知&#xff0c;参…

芯驰D9评测(2)--系统环境配置连接

linux开发板的软件开发三件套&#xff1a; 建立连接-->建立交叉编译环境-->建立驱动开发环境。 如果我们不涉及镜像的深度定制&#xff0c;只是平台化应用的话 1. 建立串口连接 查看手册&#xff0c; 获取接口定义说明&#xff1a; 板载一共两个端子&#xff0c;三个…

2023年山东省安全员C证证考试题库及山东省安全员C证试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年山东省安全员C证证考试题库及山东省安全员C证试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上岗证考试大…

Flutter笔记:手写并发布一个人机滑动验证码插件

Flutter笔记 手写一个人机滑块验证码 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/article/details/133529459 写 Flut…

备忘录:Docker基础操作与常用命令

文章目录 Docker基础操作1.1 Docker在线安装1.1.1 安装基础软件包1.1.2 安装docker主程序1.1.2.1 设置国内源1.1.2.2 安装docker 1.2 Docker离线安装1.2.1 下载离线安装包1.2.2 安装docker依赖包以及docker 1.3 设置自启动并启动dokcer1.4 安装docker-compose1.4.1 命令行下载文…

解决nvm切换node版本失败的终极办法-秒杀网上99%的水文

nvm是一款强大的node多版本管理器&#xff0c;可以轻易选择你需要的node版本&#xff0c;这对win7平台简直就是超好的福音&#xff1a;可以突破node 14.15以上的安装限制。 但是nvm安装有一个巨大的坑点&#xff1a;nvm use 版本号以后&#xff0c;并没有生效&#xff0c;nvm …

uni-app:js修改元素样式(宽度、外边距)

效果 代码 1、在<view>元素上添加一个ref属性&#xff0c;用于在JavaScript代码中获取对该元素的引用&#xff1a;<view ref"myView" id"mybox"></view> 2、获取元素引用 &#xff1a;const viewElement this.$refs.myView.$el; 3、修改…

认识柔性数组

在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 限制条件是&#xff1a; 结构体中最后一个成员未知大小的数组 1.柔性数组的形式 那么我们怎样写一个柔性数组呢 typedef struct st_type {int i;int a[0];//柔性数组成员 }ty…

HTTP协议,请求响应

、概述 二、HTTP请求协议 三、HTTP响应协议 四、请求数据 1.简单实体参数 RequestMapping("/simpleParam")public String simpleParam(RequestParam(name "name" ,required false ) String username, Integer age){System.out.println (username "…

免杀对抗-DLL劫持免杀

C&Py-DLL劫持-语言-调用加载 1.使用visual studio创建项目 2.将文件名重命名为.c后缀 3.将如下加载器代码生成dll文件 加载器代码&#xff1a; #include "pch.h" #include <Windows.h> #include <stdio.h> #include <string.h>#pragma comment…

【C语言】汉诺塔 —— 详解

一、介绍 汉诺塔&#xff08;Tower of Hanoi&#xff09;&#xff0c;又称河内塔&#xff0c;是一个源于印度古老传说的益智玩具。大焚天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。 大焚天命令婆罗门把圆盘从下面开始按…

Pikachu靶场——不安全的文件下载(Unsafe Filedownload)

文章目录 1. Unsafe Filedownload1.1 Unsafe Filedownload1.1.1 源代码分析1.1.2 漏洞防御 1.2 不安全的文件下载防御措施 1. Unsafe Filedownload 不安全的文件下载概述&#xff1a; 文件下载功能在很多web系统上都会出现&#xff0c;一般我们当点击下载链接&#xff0c;便会…

【正点原子】无法打开 源 文件 “linux/time_types.h“ (dependency of “linux/ide.h“)

问题描述 在VS code中些驱动代码时显示&#xff1a; 检测到 #include 错误。请更新 includePath。已为此翻译单元(/home/alientek/linux/atk-mp1/Linux_Drivers/2_LED/led.c)禁用波形曲线。C/C(1696) 无法打开 源 文件 "linux/time_types.h" (dependency of "…

性格敏感怎么办?改变性格敏感的方法有哪些?

有这么一群人&#xff0c;他们的情绪很容易受到外界的影响&#xff0c;就像一汪宁静的湖水&#xff0c;被风轻易地吹出皱纹。他们有着高度敏感的神经&#xff0c;外界稍微一点风吹草动&#xff0c;就会牵动他们紧张的情绪。 他们的思维就像脱缰的野马&#xff0c;生活中任何一…

第15届蓝桥STEMA测评真题剖析-2023年8月20日Scratch编程中级组

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第155讲。 第15届蓝桥第1次STEMA测评&#xff0c;这是2023年8月20日举办的STEMA&#xff0c;比赛仍然采取线上形式。这…

UWB高精度定位系统:引领精准定位技术的新纪元

在现代社会中&#xff0c;精准定位技术对于各行各业都至关重要。为了满足对高精度定位的需求&#xff0c;超宽带&#xff08;Ultra-Wideband, UWB&#xff09;技术应运而生。UWB高精度定位系统以其出色的定位精度和多样化的应用领域而备受关注。本文将深入探讨UWB高精度定位系统…

MAC手动修复『已损坏』问题 终端运行命令报错处理

安装一些第三方软件会出现已损坏的报错提醒&#xff0c;需要用命令sudo xattr -rd com.apple.quarantine进行修复&#xff0c;但是终端提示命令错误&#xff0c;怎么版 错误有几种&#xff1a; No module named ‘pkg_resources’ 这是mac电脑上python2&#xff0c;python3并…