VerilogHDL常用的仿真知识
在描述完电路之后,我们需要进行对代码进行验证,主要是进行功能验证。现在验证大多是基于UVM平台写的systemverilog,然而我并不会sv,不过我会使用verilog进行简单的验证,其实也就是所谓的仿真。这里就来记录一下一些验证的基础吧。
一、验证基础与仿真原理
①综合中的语法,都适用于仿真,在仿真中,Verilog语句是串行的,其面向硬件的并行特性则是通过其语义(语言含义)来实现的,因此并不会丢失代码的并行含义和特征。
②仿真的关键元素有:仿真时间、事件驱动、队列、调度等。
③仿真时间:指由仿真器维护的时间值,用来对仿真电路所用的真实时间进行建模。0时刻被称为仿真起始时刻。当仿真时间推进到某一个时间点时,该时间点就被称为当前仿真时间,而以后的任何时刻都被称为未来的仿真时间。
本质上,仿真时间是没有时间单位的,由于代码中有`timescale语句的定义,就出现了xxxns。
仿真事件都是严格按照仿真时间向前推进的,如果在同一个仿真时刻有多个事件要执行,那么首先需要根据他们之间的优先级来判定谁先执行。优先级相同,可能随机执行,也可能按照代码的顺序来执行。
④事件驱动:仿真时间只能被下面事件中的一种来推进:
·定义过的门级或者线传输延时;
·更新时间;
·“#”的事件控制;
·“always”关键字引入的事件控制
·“wait”的等待语句
⑤事件队列与调度:事件队列与调度可以简单地理解为:它决定了verilog在某个时刻先完成哪些语句。
VerilogHDL的分层事件队列为:
当前仿真时间事件 |
活跃事件(顺序随机或者按照代码出现的顺序) |
阻塞赋值; 连续赋值; 非阻塞赋值的右式计算; 原语输入计算和输出改变; 系统任务:$display |
非活跃事件 |
显示0延时赋值; Verilog的PLI call back例程 |
|
非阻塞赋值更新时间 |
非阻塞赋值产生一个非阻塞更新时间,被调度到当前仿真时间 |
|
监控事件 |
$monitor和$strobe系统任务,监控时间不能生成任何其他的事件,这是也要注意的。 |
|
将来仿真时间事件 |
将来事件 |
被调度到将来仿真时间的时间。 |
⑥关于forever、force和release、wait、UDP、PLI等具体语法我就不想记录了,没那个心思...
⑦系统任务的使用:
在Verilog HDL 语言中,以“$”字符开始的标识符表示系统任务或系统函数。系统任务和函数即在语言中预定义的任务和函数。和用户自定义任务和函数类似,系统任务可以返回0 个或多个值,且系统任务可以带有延迟。系统任务的功能非常强大,主要分为以下几类:
A、显示任务(display task);
B、文件输入/输出任务(File I/O task);
C、时间标度任务(timescale task);
D、仿真控制任务(simulation control task);
E、时序验证任务(timing check task);
F、仿真时间函数 (simulation time function)
G、实数变换函数(conversion functions for real);
H、概率分布函数(probabilistic distribution function)
由于时间关系,我不进行详述记录了,用到的时候再进行记录。
二、测试文件的激励
(1)信号的初始化问题
主要有三种产生激励的方法:一种是直接编辑测试激励波形(这种基本上被淘汰了),一种是用Verilog测试代码的时序控制功能,产生测试激励。还有就是利用Verilog HDL 语言的读文件功能,从文本文件中读取数据(该数据可以通过C/C++、MATLAB 等软件语言生成)。
①代码中的变量的初始化可以用initial进行初始化,也可以在定义的时候进行初始化。
②在硬件系统中,当系统上电之后,信号电平不是0就是1,不会存在x或者z,这是就会根据EDA的默认状态进行默认的设置。由于上电的默认性,导致这个默认信号不一定是我们想要的信号,因此我们需要进行复位进行初始化。
③在Verilog HDL 中,有两种不同的原因可能导致信号值为x。第一种原因是,有两个不同的信号源用相同的强度驱使同一个节点,并试图驱动成不同的逻辑值,这一般是由设计错误造成的。第二种原因是信号值没有初始化。所以在设计组合逻辑时,需要将不确定的输入转化成确定输入,然后再完成组合逻辑。
(2)时钟信号的生成
①普通时钟信号
所谓的普通时钟信号就指的是占空比为50%的时钟信号,也是最常用的时钟信号,其波形下图所示:
占空比为50%的时钟信号
普通时钟信号可通过initial 语句和always 语句产生,其代码如下:
----基于initial 语句的方法:
parameter clk_period = ;
reg clk;
initial begin
clk = ;
forever
# (clk_period/) clk = ~clk;
end
---基于always 语句的方法:
parameter clk_period = ;
reg clk;
initial
clk = ; always # (clk_period/) clk = ~clk;
在这里的initial 语句用于初始化clk 信号,否则就会出现对未知信号取反的情况,因而造成clk信号在整个仿真阶段都为未知状态。
②自定义占空比的时钟信号
自定义占空比信号通过always 模块可以快速实现,下面给出一个占空比为40%的时钟信号代码:
parameter High_time = ,
Low_time = ; //占空比为High_time/( High_time+ Low_time)
reg clk;
always begin
clk = ;
#High_time;
clk = ;
#Low_time;
end
这里由于直接对clk 信号赋值,所以不需要initial 语句初始化clk 信号。当然,这种方法也可以用于产生普通时钟信号,只是代码行数较多而已。
③相位偏移的时钟信号
相位偏移是两个时钟信号之间的相对概念,下图所示,其中clk_a 为参考信号,clk_b为偏移信号:
首先通过一个always 模块产生参考时钟clk_a,然后通过延迟赋值得到clk_b 信号,其偏移的相位可通过360*pshift_time%(High_time+Low_time)来计算,其中%为取模运算。
下面代码的相位偏移为72 度:
parameter High_time = ,
Low_time = ,
pshift_time = ; reg clk_a;
wire clk_b; always begin
clk_a = ;
# High_time;
clk_b = ;
# Low_time;
end assign # pshift_time clk_b = clk_a;
④固定数目的时钟信号
上述语句产生的时钟信号都是无限个周期的,也可以通过repeat 语句来产生固定个数的时钟脉冲,下面的代码产生了5 个周期的时钟:
parameter clk_cnt = ,
clk_period = ;
reg clk; initial begin
clk = ;
repeat (clk_cnt)
# clk_period/ clk = ~clk;
end
(3)复位信号的产生
①异步复位信号
异步复位信号的实现代码如下,代码将产生低有效的复位信号rst_n,其复位时间为100 个仿真单位:
parameter rst_repiod = ;
reg rst_n; initial begin
rst_n = ;
# rst_repiod;
rst_n = ;
end
②同步复位
同步复位信号的实现代码如下:
parameter rst_repiod = ;
reg rst_n; initial begin
rst_n = ;
@( posedge clk);
rst_n = ;
# rst_repiod;
@( posedge clk);
rst_n = ; end
上述代码首先将复位信号rst_n 初始化为1,然后等待时钟信号clk 的上升沿,将rst_n拉低,进入有效复位状态;然后经过100 个仿真周期,等待下一个上升沿到来后,将复位信号置为1。在仿真代码中,是不存在逻辑延迟的,因此在上升沿对rst_n 的赋值,能在同一个沿送到测试代码逻辑中。
在需要复位时间为时钟周期的整数倍时,可以将rst_repiod 修改为时钟周期的3 倍来实现,也可以通过下面的代码来完成。
parameter rst_num = ;
initial begin
rst_n = ;
@(posedge clk);
rst_n = ;
repeat(rst_num) @(posedge clk);
rst_n = ;
end
上述代码在clk 的第一个上升沿开始复位,然后经过5 个时钟上升沿后,在第5 个时钟上升沿撤销复位信号,进入有效工作状态。
(4)数据的产生
数据的产生这里就不进行描述了,在以后关于常用的仿真模块中进行记录。
三、提高仿真时间的注意点
①减少层次结构
仿真代码的层次越少,执行时间就越短。这主要是由于参数在模块端口之间传递需要消耗仿真器的执行时间。
②减少门级代码的使用
由于门级建模属于结构级建模,自身参数建模已经比较复杂了,还需要通过模块调用的方式来实现,因此建议仿真代码尽量使用行为级语句,建模层次越抽象,执行时间就越短。引申一点,在行为级代码中,尽量使用面向仿真的语句。例如,延迟两个仿真时间单位,最好通过“#2”来实现,而不是通过深度为2 的移位寄存器来实现。
③仿真精度越高,效率越低
例如包含`timescale 1ns / 1ps 定义的代码执行时间就比包含`timescale 1ns / 1ns 定义的代码执行时间长。
④进程越少,效率越高
代码中的语句块越少仿真越快,例如将相同的逻辑功能分布在两个always 语句块中,其仿真执行时间就比利用一个always 语句来实现的代码短。这是因为仿真器在不同进程之间进行切换也需要时间。
⑤减少仿真器的输出显示
Verilog HDL 语言包含一些系统任务,可以在仿真器的控制台显示窗口输出一些提示信息。虽然其对于软件调试是非常有用的,但会降低仿真器的执行效率。因此,在代码中这一类系统任务不能随意使用。本质上来讲,减少代码执行时间并不一定会提高代码的验证效率。
关于仿真的其他入门知识,比如一些无规律信号的生成、测试结果的存储和显示等问题,我会在后面进行记录,主要是以代码模块的形式记录。
VerilogHDL常用的仿真知识的更多相关文章
- Ext常用开发基础知识
Ext常用开发基础知识 组件定义 //这种方法可以缓存所需要的组件 调用起来比较方便(方法一 ) Ext.define('MySecurity.view.home.HomePanel', { //添加 ...
- Web测试的常用测试用例与知识
1. Web测试中关于登录的测试 2. 搜索功能测试用例设计 3. 翻页功能测试用例 4. 输入框的测试 5. Web测试的常用的检查点 6. 用户及权限管理功能常规测试方法 7. Web测试之兼容性 ...
- VCS使用学习笔记(1)——Verilog相关的仿真知识
本文主要学习Verilog的仿真特性,以及仿真器对Verilog的处理,算是对Verilog知识的增量学习.本文内容与我的另一篇博文(http://www.cnblogs.com/IClearner/ ...
- 开发中常用的es6知识
结合实际开发,开发中常用的es6的知识: 1.新增let和const命令: ES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效: cons ...
- linux运维常用命令及知识
1.查找当前目录下所有以.tar结尾的文件然后移动到指定目录: find . -name “*.tar” -exec mv {} ./backup/ ; 查找当前目录30天以前大于100M的LOG文件 ...
- AIX 常用命令和知识
BOOTLIST:#bootlist -m normal -o (查看bootlist)#bootlist -m normal (设置bootlist为空,谁要在我机器上执行我就要哭了)#boot ...
- 常用的flex知识 ,比起float position 好用不少
flex布局具有便捷.灵活的特点,熟练的运用flex布局能解决大部分布局问题,这里对一些常用布局场景做一些总结. web页面布局(topbar + main + footbar) 示例代码 要 ...
- 那些你常用的JSP知识
脚本程序 <> 或者,您也可以编写与其等价的XML语句,就像下面这样: <jsp:scriptlet> 代码片段 </jsp:scriptlet>任何文本.HTML ...
- 10个MCU常用的基础知识
转自:http://bbs.21ic.com/icview-2659278-1-1.html 1.MCU有串口外设的话,在加上电平转换芯片,如MAX232.SP3485就是RS232和RS485接口了 ...
随机推荐
- div中内容无法自动换行问题
.l-text{ padding:.3em .5em; width:67%; height: auto; /*height:1.3em;*/ border:.1em #2294C3 solid; bo ...
- XAML: 获取元素的位置
在之前讨论 ListView 滚动相关需求的文章中(UWP: ListView 中与滚动有关的两个需求的实现)曾经提到了获取元素相对位置的方法,即某元素相对另一元素的位置.现将所有相关方法再作整理,并 ...
- web移动端布局方式整理
写H5页面一直写的有点随意,只是保证了页面在各个屏幕下显示良好,却没有保证到在各个屏幕下是等比例放大或者缩小.这些天在写一些页面,试着看看能不能写出等比例放大缩小的页面,发现不容易啊,在网上找了一些文 ...
- java 读取excel
1. 需要下载jxl.jar包 自己研究了一下,代码如下 package file;import java.io.File;import java.io.IOException;import java ...
- laravel中token的使用方式
在form表单里提交表单时,可 <form action="" method="post"> <?php echo csrf_field() ...
- Java+XSL合并多个XML文件
使用 Java 解析 XML 文件有许多成熟的工具,如 dom4j 等等.但在一些场景中,我们可能使用 Ant.Maven 等构建工具对多个 XML 文件进行合并,我们希望可以直接通过脚本文件,或者简 ...
- 9天C#转Java学习过程,自己记录一下
其实没有完整的9天,就是连续每天花点时间,过程so frustrated,踩坑无数...下面是学习过程的记录 第1天 开始正式学习JavaEE,已完成: 1. Tomcat安装: 2. Tomcat配 ...
- dos命令窗口修改编码,CMD编码修改方法
dos命令窗口修改编码,CMD编码修改方法 第一步,打开命令窗口有两种方法第一种:可以点击左下角的开始按钮,在运行里面输入CMD,然后敲回车2第二种:组合键WIN+R键,组合键后就会弹出窗口,然后输入 ...
- Android如何实现定位获取
一:GPS定位: (1).要实用Adnroid平台的GPS设备,首先需要添加上权限,所以需要添加如下权限: uses-permission android:name= android.permissi ...
- String,StringBuffer与StringBuilder
1. String,StringBuffer与StringBuilder的区别 String:存储在常量池中:是不可变的字符序列,任何对String值的改变都会引发新的String对象的生成,因此执行 ...