VerilogHDL常用的仿真知识

2024-04-04 16:58

本文主要是介绍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 = 10;
reg clk;
initial beginclk = 0;forever# (clk_period/2) clk = ~clk;
end
复制代码

 

---基于always 语句的方法:

parameter  clk_period = 10;
reg clk;
initial clk = 0;always # (clk_period/2) clk = ~clk;

 

在这里的initial 语句用于初始化clk 信号,否则就会出现对未知信号取反的情况,因而造成clk信号在整个仿真阶段都为未知状态。

  ②自定义占空比的时钟信号

自定义占空比信号通过always 模块可以快速实现,下面给出一个占空比为40%的时钟信号代码:

复制代码
parameter High_time = 4,Low_time = 6;  //占空比为High_time/( High_time+ Low_time)
reg clk;
always beginclk = 1;#High_time;clk = 0;#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 = 5, Low_time = 5,pshift_time = 2;reg clk_a;
wire clk_b;always beginclk_a = 1;# High_time;clk_b = 0;# Low_time;
endassign # pshift_time clk_b = clk_a;
复制代码

 

  ④固定数目的时钟信号

上述语句产生的时钟信号都是无限个周期的,也可以通过repeat 语句来产生固定个数的时钟脉冲,下面的代码产生了5 个周期的时钟:

复制代码
parameter clk_cnt = 5, clk_period = 2;
reg clk;initial beginclk = 0;repeat (clk_cnt)# clk_period/2 clk = ~clk;
end    
复制代码

 

 

(3)复位信号的产生

  ①异步复位信号

异步复位信号的实现代码如下,代码将产生低有效的复位信号rst_n,其复位时间为100 个仿真单位:

复制代码
parameter rst_repiod = 100;
reg rst_n;initial beginrst_n = 0;# rst_repiod;rst_n = 1;
end
复制代码

 

 

 

  ②同步复位

同步复位信号的实现代码如下:

复制代码
parameter rst_repiod = 100;
reg rst_n;initial beginrst_n = 1;@( posedge clk);rst_n = 0;# rst_repiod;@( posedge clk);rst_n = 1;end    
复制代码

 

上述代码首先将复位信号rst_n 初始化为1,然后等待时钟信号clk 的上升沿,将rst_n拉低,进入有效复位状态;然后经过100 个仿真周期,等待下一个上升沿到来后,将复位信号置为1。在仿真代码中,是不存在逻辑延迟的,因此在上升沿对rst_n 的赋值,能在同一个沿送到测试代码逻辑中。

  在需要复位时间为时钟周期的整数倍时,可以将rst_repiod 修改为时钟周期的3 倍来实现,也可以通过下面的代码来完成。

复制代码
parameter rst_num = 5;
initial beginrst_n = 1;@(posedge clk);rst_n = 0;repeat(rst_num)  @(posedge clk);rst_n = 1;
end
复制代码

 

上述代码在clk 的第一个上升沿开始复位,然后经过5 个时钟上升沿后,在第5 个时钟上升沿撤销复位信号,进入有效工作状态。

 

 

(4)数据的产生

数据的产生这里就不进行描述了,在以后关于常用的仿真模块中进行记录。

 

三、提高仿真时间的注意点

  ①减少层次结构

  仿真代码的层次越少,执行时间就越短。这主要是由于参数在模块端口之间传递需要消耗仿真器的执行时间。

②减少门级代码的使用

  由于门级建模属于结构级建模,自身参数建模已经比较复杂了,还需要通过模块调用的方式来实现,因此建议仿真代码尽量使用行为级语句,建模层次越抽象,执行时间就越短。引申一点,在行为级代码中,尽量使用面向仿真的语句。例如,延迟两个仿真时间单位,最好通过“#2”来实现,而不是通过深度为2 的移位寄存器来实现。

  ③仿真精度越高,效率越低

  例如包含`timescale 1ns / 1ps 定义的代码执行时间就比包含`timescale 1ns / 1ns 定义的代码执行时间长。

  ④进程越少,效率越高

  代码中的语句块越少仿真越快,例如将相同的逻辑功能分布在两个always 语句块中,其仿真执行时间就比利用一个always 语句来实现的代码短。这是因为仿真器在不同进程之间进行切换也需要时间。

  ⑤减少仿真器的输出显示

  Verilog HDL 语言包含一些系统任务,可以在仿真器的控制台显示窗口输出一些提示信息。虽然其对于软件调试是非常有用的,但会降低仿真器的执行效率。因此,在代码中这一类系统任务不能随意使用。本质上来讲,减少代码执行时间并不一定会提高代码的验证效率。

 

  关于仿真的其他入门知识,比如一些无规律信号的生成、测试结果的存储和显示等问题,我会在后面进行记录,主要是以代码模块的形式记录。

这篇关于VerilogHDL常用的仿真知识的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/876341

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

常用的jdk下载地址

jdk下载地址 安装方式可以看之前的博客: mac安装jdk oracle 版本:https://www.oracle.com/java/technologies/downloads/ Eclipse Temurin版本:https://adoptium.net/zh-CN/temurin/releases/ 阿里版本: github:https://github.com/

30常用 Maven 命令

Maven 是一个强大的项目管理和构建工具,它广泛用于 Java 项目的依赖管理、构建流程和插件集成。Maven 的命令行工具提供了大量的命令来帮助开发人员管理项目的生命周期、依赖和插件。以下是 常用 Maven 命令的使用场景及其详细解释。 1. mvn clean 使用场景:清理项目的生成目录,通常用于删除项目中自动生成的文件(如 target/ 目录)。共性规律:清理操作

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

019、JOptionPane类的常用静态方法详解

目录 JOptionPane类的常用静态方法详解 1. showInputDialog()方法 1.1基本用法 1.2带有默认值的输入框 1.3带有选项的输入对话框 1.4自定义图标的输入对话框 2. showConfirmDialog()方法 2.1基本用法 2.2自定义按钮和图标 2.3带有自定义组件的确认对话框 3. showMessageDialog()方法 3.1