【必看】时序逻辑仿真成组合逻辑?你知道原因吗?
对于初学者,一般会遇到这种情况,明明写的时序逻辑,结果仿真结果却是组合逻辑,然后看遍设计代码,始终找不到原因,交流群、知乎这种问题随处可见。但不要怀疑软件问题,modelsim这些专用软件基本不会遇见软件自身问题,原因其实很简单,因为多数人只关注设计文件不会关注TestBentch的合理性,导致找不到问题原因,后文分析原因并给出避免这种问题的方法。
在仿真时经常会使用“#”和“@(posedge clk)”来实现延迟,“#”后面跟数字,表示延迟数字对应最小的时间单位,而“@(posedge clk)”则用来检测clk信号上升沿,如果CYCLE表示始终周期对应的时间长度,那么“#(CYCLE)”表示延迟一个时钟周期长度的时间。在时钟上升沿输出数据后,使用“@(posedge clk)”,会延迟到下个时钟上升沿,同样也可以表示延迟一个时钟周期,那有没有区别?
分析以下代码,输出dout就是两个输入dataa与datab相加,由于是时序逻辑,dout会延迟dataa或datab变化后的一个时钟周期。
module add( input clk ,//系统时钟; input rst_n ,//系统复位,低电平有效; input [3 : 0] data_a ,//加数dataa; input [3 : 0] data_b ,//加数datab; output reg [4 : 0] dout );always@(posedge clk or negedge rst_n)begin if(rst_n==1'b0)begin//初始值为0; dout <= 4'd0; end else begin dout <= data_a + data_b; end endendmodule
Testbench如下所示:
`timescale 1 ns/1 ns
module test(); parameter CYCLE = 10 ;//系统时钟周期,单位ns,默认10ns; parameter RST_TIME = 5 ;//系统复位持续时间; parameter STOP_TIME = 100 ;//仿真运行时间,复位完成后运行100个系统时钟后停止; reg clk ;//系统时钟,默认100MHz; reg rst_n ;//系统复位,默认低电平有效; reg [3 : 0] data_a; reg [3 : 0] data_b;wire [4 : 0] dout ; add u_add ( .clk ( clk ), .rst_n ( rst_n ), .data_a ( data_a ), .data_b ( data_b ), .dout ( dout ) ); //生成周期为CYCLE数值的系统时钟; initial begin clk = 1; forever #(CYCLE/2) clk=~clk; end//生成复位信号; initial begin rst_n = 1; #2; rst_n = 0;//开始时复位10个时钟; #(RST_TIME*CYCLE); rst_n = 1; end //生成输入信号din; initial begin data_a = 0;data_b=0;//输入数据初始化为0; #(10*CYCLE);//延迟10个时钟周期; repeat(STOP_TIME)begin//循环STOP_TIME次;#(CYCLE); data_a = {$random} % 16; data_b = {$random} % 16; end $stop;//停止仿真; endendmodule
使用modelsim仿真如下图所示,奇怪的是为什么时序逻辑仿真成组合逻辑了?

分析:加法器代码肯定是没有问题的,modelsim软件也是经过fpga设计以及IC设计人员多年使用,是最常用的仿真工具,也不可能出现这样的低级bug。如果你把代码下载到开发板上,使用在线逻辑分析仪抓取数据,能够得到正确的运行结果,但是仿真就是错误的。这是为什么?那就只剩下写的testbench文件了,来看下testbench与输出相关的信号,首先时钟和复位信号是没有问题的,那就只剩下dataa与datab的产生模块了,如下所示:
//生成输入信号din;
initial begin data_a = 0;data_b=0;//输入数据初始化为0; #(10*CYCLE);//延迟10个时钟周期; repeat(STOP_TIME)begin//循环STOP_TIME次;#(CYCLE); data_a = {$random} % 16; data_b = {$random} % 16; end $stop;//停止仿真;
end
开始仿真时两个输入信号都被赋值为0,经10个时钟延迟之后进入forever循环内,每次循环之前都会把数据延迟一个时钟周期,然后在对两个输入信号赋一个0~15的随机值。逻辑上其实没有问题,但是注意一个问题,每次给dataa和datab赋值时间与时钟clk上升沿是对齐的,导致D触发器的输入信号在时钟上升沿时发生变化,由此导致D触发器数据采集错误,最终导致D触发器输出信号dout提前更新数据。这里实际上与保持时间违例有点类似,D触发器的下一个输入数据来得过快,影响了上一个数据的采集。
解决方法很简单,因为是数据刚好在时钟上升沿时发生更新导致D触发器数据采集错误,那么把两个输入数据全部延迟一点不就行了,修改如下,将两个输入数据的所有变化均延迟1ns,与时钟上升沿错开。
//生成输入信号din;
initial begin #1; data_a = 0;data_b=0;//输入数据初始化为0; #(10*CYCLE);//延迟10个时钟周期; repeat(STOP_TIME)begin//循环STOP_TIME次; #(CYCLE); data_a = {$random} % 16; data_b = {$random} % 16; end $stop;//停止仿真;
end
修改后仿真结果如下:

从上面仿真结果就可以看到,dataa与datab的变化都延迟时钟上升沿1ns之后,就没有在影响仿真结果了。这也是为什么很多代码在对信号赋值之前会延迟1ns的原因,就是为了数据变化与时钟上升沿错开,避免发生上面这种由于testbench书写问题所引发的离奇结果。
使用“#”会引发上面问题,那如果过使用“@(posedge clk)”这种写法还会出现那样的仿真结果?
先给答案,不会出现类似问题,因为“@(posedge clk)”表示已经检测到时钟上升沿了,那么在这之后更新的数据自然与时钟上升沿就是错开的了。
同样的案例,只是把dataa和datab赋值的部分改成如下代码。
//生成输入信号din;
initial begin data_a = 0;data_b=0;//输入数据初始化为0; #(10*CYCLE);//延迟10个时钟周期; repeat(STOP_TIME) @(posedge clk)begin//循环STOP_TIME次; data_a = {$random} % 16; data_b = {$random} % 16; end $stop;//停止仿真;
end
上面代码表达结果与下面代码一致。
//生成输入信号din;
initial begin data_a = 0;data_b=0;//输入数据初始化为0; #(10*CYCLE);//延迟10个时钟周期; repeat(STOP_TIME)begin//循环STOP_TIME次; @(posedge clk); data_a = {$random} % 16; data_b = {$random} % 16; end $stop;//停止仿真;
end
仿真结果如下,没有出现任何问题,数据变化近似与时钟上升沿对齐,但是输出数据dout没有受到影响,这就是“@(posedge clk)”的效果。

“#”和“@(posedge clk)”虽然都可以写成延时几个时钟周期的形式,但是他们是有区别的,区别在与“#”延迟与时钟其实没有关系,就有可能和时钟上升沿重合,这是使用是需要注意的,建议在仿真开始时就对数据延迟1ns然后在赋值,与时钟信号变化错位。而“@(posedge clk)”本质是检测时钟上升沿,在时钟上升沿之后才会去执行后面的语句,所以数据变化与时钟上升沿变化是错位的,不会出现“#”那种问题。
上述从效果看肯定是使用“@(posedge clk)”,作为延迟更好,使用“#(CYCLE)”延迟一个时钟更号理解,但是要注意可能遇到的问题,一般使用模板时,赋值语句开头会带有“#1;”,或者在每次赋值前用“@(posedge clk)”作为延迟,如下我常用赋值模板。
//生成输入信号din;
initial begin #1;din = 0;//输入数据初始化为0; #(10*CYCLE);//延迟10个时钟周期; end
相关文章:
【必看】时序逻辑仿真成组合逻辑?你知道原因吗?
对于初学者,一般会遇到这种情况,明明写的时序逻辑,结果仿真结果却是组合逻辑,然后看遍设计代码,始终找不到原因,交流群、知乎这种问题随处可见。但不要怀疑软件问题,modelsim这些专用软件基本不…...
PyTorch翻译官网教程-LANGUAGE MODELING WITH NN.TRANSFORMER AND TORCHTEXT
官网链接 Language Modeling with nn.Transformer and torchtext — PyTorch Tutorials 2.0.1cu117 documentation 使用 NN.TRANSFORMER 和 TORCHTEXT进行语言建模 这是一个关于训练模型使用nn.Transformer来预测序列中的下一个单词的教程。 PyTorch 1.2版本包含了一个基于论…...
SpringBoot复习:(43)如何以war包的形式运行SpringBoot程序
一、.pom.xml配置packging为war <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven…...
Dubbo高手之路2,6种扩展机制详解
目录 一、Dubbo扩展机制的概述二、Dubbo的自适应扩展机制1. 什么是自适应扩展机制2. 自适应扩展机制的使用示例 三、Dubbo的SPI扩展机制1. 什么是SPI扩展机制2. SPI扩展机制的使用示例3. Dubbo的SPI扩展机制中自定义扩展点的实现示例 四、Dubbo的自定义扩展点机制1. 什么是自定…...
C语言快速回顾(二)
前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》,结合我自己的工作学习经历,我准备写一个音视频系列blog。C/C是音视频必…...
ADB连接安卓手机提示unauthorized
近期使用airtest进行自动化测试时,因为需要连接手机和电脑端,所以在使用adb去连接本人的安卓手机vivo z5时,发现一直提示unauthorized。后来经过一系列方法尝试,最终得以解决。 问题描述: 用数据线将手机接入电脑端&…...
【软件工程】内聚
概念 是指一个模块内部个成分之间相互关联程度的度量。也就是说,凝聚是对模块内各处理动作组合强度的一种度量。很显然,一个模块的内聚越大越好。 偶然凝聚 一个模块内的各处理元素之间没有任何联系,只是偶然地被凑到一起。这种模块也称为…...
支持对接鸿蒙系统的无线模块及其常见应用介绍
近距离的无线通信得益于万物互联网的快速发展,基于集成部近距离无线连接,为固定和移动设备建立通信的蓝牙技术也已经广泛应用于汽车领域、工业生产及医疗领域。为协助物联网企业终端产品能快速接入鸿蒙生态系统,SKYLAB联手国产芯片厂家研发推…...
java项目打包运行报异常:Demo-1.0-SNAPSHOT.jar中没有主清单属性
检查后发现pom文件中有错误,需要添加build内容才能恢复正常。 添加下面文件后再次启动恢复正常。 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactI…...
nginx+keepalived实现负载均衡和高可用
环境准备 IPVIP环境客户端192.168.134.174Master192.168.134.170192.168.134.100需要配置nginx负载均衡Backup192.168.134.172192.168.134.100需要配置nginx负载均衡web1服务器192.168.134.171 web2服务器 192.168.134.173 1、首先安装nginx服务器(此处采用yum安装…...
微信小程序实现图片多点裁剪
话不多说,直接上代码 1、页面布局 <view class"buttons" style"height: 50px;"><view class"upload btn" style"background-color: #d18118;"bindtap"uploadImage"> 上传图片 </view><vie…...
计算图片的均值和方差用图片的归一化取值
计算图片的均值和方差用图片的归一化取值 注意:使用这种方法的前提是进行了数据批量化操作,需要使用神经网络库,torch,DataLoader def getStat(data):print(len(data))loader torch.utils.data.DataLoader(data, batch_size1, …...
预测算法|改进粒子群算法优化极限学习机IDM-PSO-ELM
回归拟合: 分类 本文是作者的预测算法系列的第四篇,前面的文章中介绍了BP、SVM、RF及其优化,感兴趣的读者可以在作者往期文章中了解,这一篇将介绍——极限学习机 过去的几十年里基于梯度的学习方法被广泛用于训练神经网络&am…...
小黑子—JavaWeb:第六章 - Filter、Listener、AJAX与JSON
JavaWeb入门6.0 1. Filter1.1 Filter快速入门1.2 Filter执行流程1.3 Filter拦截路径配置1.4 Filter过滤器链1.5 案例登录验证 2. Listener2.1 ServletContextListener使用 3. AJAX3.1 AJAX 快速入门3.2 案例 验证用户名是否存在3.3 Axios 异步框架3.3.1 Axios 快速入门3.3.2 Ax…...
STM32 LL库开发
一、STM32开发方式 标准库开发:Standard Peripheral Libraries,STDHAL库开发:Hardware Abstraction Layer,硬件抽象层LL库开发:Low-layer,底层库 二、HAL库与LL库开发对比 ST在推行HAL库的时候,…...
标记垃圾,有三种色彩:四千长文带你深入了解三色标记算法
🔭 嗨,您好 👋 我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏&…...
277/300 React+react-router-dom+Vite 二级页面刷新时,白屏问题解决
(一)方案 BrowserRouter 换为 HashRouter (二)代码 import routes from ./routes import {ReactElement, Suspense} from react import {createHashRouter, Navigate} from react-router-dom // 生成路由数据 const generateR…...
如何做线上监控
1、背景 软件的质量是需要全生命周期进行关注的,在生产环境下QA的活动就是测试右移,测试右移最关键的手段就是线上监控,也是至关重要的一个环节,可以通过技术的手段,提前感知到线上问题和风险,先于用户提前发现问题,提升服务可感知性,从而降低客户投诉。 2、通用原则…...
饥荒开服教程——游戏
饥荒开服教程——游戏 1. 开服环境2. 开服步骤2.1 创建集群2.2 安装服务端2.3 上传mod2.4 启动脚本2.5 上传地图2.6 设置访问令牌2.7 修改配置 3. 服务器命令3.1 关闭服务器3.2 回档 记录一些在饥荒联机版开服中遇到过的问题。 参考:3分钟创建你的饥荒联机专属服务…...
查询 npm/yarn 安装依赖的全局路径及路径修改
一、NPM 1.查询 npm 安装依赖的全局路径 npm prefix -g 2. 修改 npm 全局安装位置 npm config set prefix "D:\nodejs\node_modules\npm\node_modules" 3. 修改 npm 全局 cache 位置 npm config set cache "D:\nodejs\node_modules\npm\cache" 4. np…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
STM32+rt-thread判断是否联网
一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
