【必看】时序逻辑仿真成组合逻辑?你知道原因吗?

2023-11-10

  对于初学者,一般会遇到这种情况,明明写的时序逻辑,结果仿真结果却是组合逻辑,然后看遍设计代码,始终找不到原因,交流群、知乎这种问题随处可见。但不要怀疑软件问题,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  
   end

endmodule

  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;//停止仿真;  
   end

endmodule

  使用modelsim仿真如下图所示,奇怪的是为什么时序逻辑仿真成组合逻辑了?
在这里插入图片描述

图1 使用#延迟仿真结果

  分析:加法器代码肯定是没有问题的,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

  修改后仿真结果如下:
在这里插入图片描述

图2 添加#1的仿真结果

  从上面仿真结果就可以看到,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)”的效果。
在这里插入图片描述

图3 使用@(posedge clk)的仿真结果

  “#”和“@(posedge clk)”虽然都可以写成延时几个时钟周期的形式,但是他们是有区别的,区别在与“#”延迟与时钟其实没有关系,就有可能和时钟上升沿重合,这是使用是需要注意的,建议在仿真开始时就对数据延迟1ns然后在赋值,与时钟信号变化错位。而“@(posedge clk)”本质是检测时钟上升沿,在时钟上升沿之后才会去执行后面的语句,所以数据变化与时钟上升沿变化是错位的,不会出现“#”那种问题。

  上述从效果看肯定是使用“@(posedge clk)”,作为延迟更好,使用“#(CYCLE)”延迟一个时钟更号理解,但是要注意可能遇到的问题,一般使用模板时,赋值语句开头会带有“#1;”,或者在每次赋值前用“@(posedge clk)”作为延迟,如下我常用赋值模板。

//生成输入信号din;  
initial begin  
   #1;din = 0;//输入数据初始化为0;  
   #(10*CYCLE);//延迟10个时钟周期;  
   
end
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【必看】时序逻辑仿真成组合逻辑?你知道原因吗? 的相关文章

  • Quartus II 安装

    本次介绍使用的 Quartus 版本为 10 1 目前 Quartus II 官网已经没有 13 1 以下版本的安装包 大家可以安装 13 1 以上版本的软件 功能都是大同小异 下载地址 FPGA Software Download Cen
  • STM32【复习串口】

    串口复习加深理解笔记 杂谈 USART FLAG TXE发送缓冲区空标志 说明可以往数据寄存器写入数据了 但并不代码数据发送完成了 USART FLAG TC发送完成标志 这个才是代表USART在缓冲区的数据发送完成了 即从机接收到了数据
  • 【Xilinx Vivado时序分析/约束系列6】FPGA开发时序分析/约束-IO时序输入延时

    目录 源同步FPGA输入时序分析的模型 input delay约束 极限input delay 往期系列博客 源同步FPGA输入时序分析的模型 以下为源同步FPGA输入时序分析的模型的示意图 在之前的文章中介绍过 在此介绍一下各个时钟延时的
  • 8x8LED点阵

    点量这个只需要把9高电平 13低电平就可以了 共阳极点阵 行线是led的正极 列线是led的列线 左上角点亮 显示多个灯是动态扫描的 一个一个显示的 然后间隔速度要快就可以造成显示 点阵由两篇74Hc595级联在一起驱动的 只需要三个io口
  • 平头哥(T-Head )开源RISCV处理器OpenC906 RTL仿真

    在过去的几年里 阿里集团平头哥陆续推出了几款RISCV处理器 有些处理器已经在产业界得到了应用 比如在某志的D1处理器中 就嵌入了平头哥的玄铁C906内核为 芯 RISCV虽然是一个开放标准 并且网络上也不乏一些开源核的RTL实现 但是商用
  • MIPI D-PHY介绍(二) FPGA

    MIPI D PHY介绍 二 FPGA 随着移动设备的广泛普及 MIPI D PHY作为其最主要的物理层标准之一 被越来越多地使用在各种嵌入式系统中 本文将详细介绍MIPI D PHY的工作原理和在FPGA设计中的实现方法 MIPI D P
  • J-Link仿真器与JTAG和SWD下载与接线

    目录 1 JTAG 1 1JTAG今天被用来主要的三大功能 1 2JTAG引脚 1 3可选引脚 2 SWD 2 1 SWD引脚 2 2 可选择引脚 2 3 JTag和SWD模式引脚定义 3 J Link仿真器 4 IAR与MDK配置两种下载
  • 【科普】波特率和比特速率的理解

    什么是波特率 单位时间内传输的码元个数称为波特率 单位为 Baud 那码元又是什么呢 码元又称为 符号 即 symbol 维基百科上对码元的解释 持续一段固定时间的通信信道有效状态就是码元 这么解释比较抽象 可以解释码元的物理意义 在通信信
  • DEBUG:Generate Bitstream失败

    问题 约束失败 解决 确保IO初始化引脚正确 和选择合适的电平
  • SD卡读写实验(SPI模式)

    对于 SD 卡的 SPI 模式而言 采用的 SPI 的通信模式为模式 3 即 CPOL 1 CPHA 1 在 SD 卡 2 0 版 本协议中 SPI CLK 时钟频率可达 50Mhz SD 卡的 SPI 模式 只用到了 SDIO D3 SP
  • MOS管的知识,看这一篇就可以了

    转载 21ic电子网 2020 11 15 18 19 以下文章来源于记得诚电子设计 作者记得诚 记得诚电子设计 分享电子硬件知识 永远相信美好的事情即将发生 今天的文章简单总结一下MOS管 如下是本文目录 场效应管分类 场效应管分为结型
  • 跨时钟域处理方法(一)——打拍

    一 说明 处理跨时钟域的数据可以分为单bit数据和多bit数据 而打拍的方法主要常见于处理单bit数据的跨时钟域问题 打拍的本质是通过添加寄存器 对输入的数据进行延拍 其主要目标是消除亚稳态的影响 常见的是打2拍 也就是添加2级寄存器 二
  • 吃透Chisel语言.18.Chisel模块详解(五)——Chisel中使用Verilog模块

    Chisel模块详解 五 Chisel中使用Verilog模块 上一篇文章讲述了用函数实现轻量级模块的方法 可以大幅度提升编码效率 Chisel中也提供了一些好用的函数 方便我们编写代码 也方便Chisel编译器优化生成的硬件电路 在Chi
  • xilinx xdma PCIe中断bug

    xilinx xdma PCIe中断存在bug bug1 此中断虽然是msi或者msx中断 但是不中断cpu bug2 此中断不是边沿中断 而是电平中断 在驱动层需要不断地轮训查询中断事件 bug3 此中断持续时间必须长 而且在收到中断应答
  • Verilog HDL——Modelsim仿真

    常用testbench语法 finish 和 stop finish任务用于终止仿真并跳出仿真器 stop任务则用于中止仿真 timescale time unit time precision time unit指定计时和延时的测量单位
  • PAJ7620U2手势识别——配置0x00寄存器(3)

    文章目录 前言 一 为啥要配置0x00寄存器 二 配置步骤 1 单个读操作步骤图 2 模块状态转移图绘制 3 模块波形图绘制 4 上板验证 5 参考代码 总结 前言 在前面的教程中 小编带领各位读者学习了如何通过I2C协议去唤醒PAJ762
  • 【FPGA】通俗理解从VGA显示到HDMI显示

    注 大部分参考内容来自 征途Pro FPGA Verilog开发实战指南 基于Altera EP4CE10 2021 7 10 上 贴个下载地址 野火FPGA Altera EP4CE10征途开发板 核心板 野火产品资料下载中心 文档 hd
  • 【FPGA多周期时序约束详解】- 解读FPGA多周期时序约束的全过程

    FPGA多周期时序约束详解 解读FPGA多周期时序约束的全过程 FPGA作为数字电路设计的常见工具 其设计中必然会遇到时序约束的问题 而多周期时序约束更是FPGA设计中不可避免的难点之一 本文将详细介绍FPGA多周期时序约束的全过程 并结合
  • 画时序图软件——TimeGen和Timing Designer下载

    在写实验报告的时候需要画波形图 但是手头没有很好的软件 就上网搜了一些 分享出来 这里分享的是TimeGen和Timing Designer两个软件 资源均来自网上 有侵权请联系 TimeGen使用和安装都比较简单 我发的应该里面有破解方法
  • Matlab图像处理系列——图像复原之噪声模型仿真

    微信公众号上线 搜索公众号 小灰灰的FPGA 关注可获取相关源码 定期更新有关FPGA的项目以及开源项目源码 包括但不限于各类检测芯片驱动 低速接口驱动 高速接口驱动 数据信号处理 图像处理以及AXI总线等 本节目录 一 图像复原的模型 二

随机推荐

  • 华为OD机试,C语言实现:IP地址整数表示

    描述 原理 ip地址的每段可以看成是一个0 255的整数 把每段拆分成一个二进制形式组合起来 然后把这个二进制数转变成 一个长整数 举例 一个ip地址为10 0 3 193 每段数字 相对应的二进制数 10 00001010 0 00000
  • 总结: C++ 中如何把输出结果写入到文件中

    文是我在网上搜到额一些经验汇总 C 把输出结果写入到文件中 文件 I O 在C 中比烤蛋糕简单多了 在这篇文章里 我会详细解释ASCII和二进制文件的输入输出的每个细节 值得注意的是 所有这些都是用C 完成的 一 ASCII 输出 为了使用
  • vue实战之Filter传入多个参数

    文章目录 前言 一 Filter多参数 1 创建全局过滤器 2 引用实现 总结 前言 vue过滤器Filter用于格式化文本 即我们日常的为数字添加 或 符号等简单操作 但在现实场景中除了 往往会有略微复杂的情况出现 如 给多个不同的循环表
  • batch normalization详解

    1 引入BN的原因 1 加快模型的收敛速度 2 在一定程度上缓解了深度网络中的 梯度弥散 问题 从而使得训练深层网络模型更加容易和稳定 3 对每一批数据进行归一化 这个数据是可以输入也可以是网络中间的某一层输出 4 网络一旦train起来
  • 改变单选按钮radio圆点的颜色

    2019独角兽企业重金招聘Python工程师标准 gt gt gt
  • 实例化和初始化的区别

    一 实例化和初始化的区别 实例化 只是单纯的把对象 new 一下就行了 例 Student st new Student 这样就行了 初始化 是在实例化之后完成的 先实例化对象 只给对象属性赋值 然后初始化这个对象
  • mybatis拦截器使用及原理

    使用拦截器 Web开发中我们经常会碰到分页操作 一个项目中或许有多处使用到分页 这时如果Java后台使用MyBatis作为持久层 我们就可以使用MyBatis的拦截器功能来完成整个项目中多处的分页操作 减少代码的冗余 拦截器代码 拦截Sta
  • modbus 协议编程 C++

    MODBUS通讯协议及编程 ModBus通讯协议分为RTU协议和ASCII协议 我公司的多种仪表都采用ModBus RTU通讯协议 如 CH2000智能电力监测仪 CH2000M电力参数采集模块 巡检表 数显表 光柱数显表等 下面就ModB
  • FastDFS分布文件系统Java客户端使用

    原文链接 http blog csdn net xyang81 article details 52847311 FastDFS分布式文件系统服务安装和使用请参考上一篇文章 FastDFS分布式文件系统安装与使用 单节点 担建环境 官网Ja
  • [1177]Hive 窗口函数之lead() over(partition by ) 和 lag() over(partition by )

    lag over 与 lead over 函数是跟偏移量相关的两个分析函数 通过这两个函数可以在一次查询中取出同一字段的前 N 行的数据 lag 和后 N 行的数据 lead 作为独立的列 从而更方便地进行进行数据过滤 这种操作可以代替表的
  • QT Event机制测试程序

    QT Event机制测试程序 代码 https github com pengrui2009 QEventTest 这里我们测试QKeyPress时间 在主窗口放置一个QLineEdit控件 并提升为MyLineEdit 新建MyLineE
  • DVWA通关教程

    1 首先先把难度调为low 进行brute force 首先审计代码
  • java中Long类型数据必须转化为int才能正确比较

    java中如果有Long类型数据需要比较判断时 必须转化为int才能正确比较 例如 Long long1 Long parseLong 1012 Long long2 Long parseLong 1012 if long1 long2 结
  • HTTP FAILED: java.net.UnknownServiceException: CLEARTEXT communication to baobab.kaiyanapp.com not

    问题 HTTP FAILED java net UnknownServiceException CLEARTEXT communication to baobab kaiyanapp com not permitted by network
  • 配置PDB符号文件服务

    配置PDB符号文件服务器的想法 刚入职的小木 前不久刚刚解决了一次crash问题 Windbg分析程序崩溃实践 小木没有松懈 继续进行项目代码和Debug技术的学习 同时也思考了一个问题 产品每隔一段时间就会发布新的版本 当出现Crash问
  • 利用Python实现一组数的最大公约数

    我先用求三个整数的最大公约数为例 首先利用for循环来进行判断这三个整数可以被那些数整除 代码如下 x y z eval input 请输入三个整数 用逗号隔开 ma max x y z ls for i in range 2 ma a x
  • 【MQTT】MQTT协议学习

    文章目录 MQTT协议 简述 特点 MQTT消息的QoS 服务质量 MQTT支持三种QoS等级 协议实现方式 MQTT协议数据包 控制报文 结构 MQTT固定头 MQTT数据包类型 标识位 剩余长度 Remaining Length MQT
  • Sqlserver 监控使用磁盘空间情况

    最近遇到一个小问题 为了保存以往的一些数据 间了大量临时表 导致SQLserver 数据增长过快 不得不想个办法监控磁盘空间使用情况 网上一般有几种办法 一是使用 dm os volume stats函数 缺点是 无法获取非数据库所在的磁盘
  • Service Bus Namespace 和 Access Control

    Service Bus Namespace 和 Access Control Service Bus Namespace简述 https yourapp servicebus windows net foo bar baz 就是一个name
  • 【必看】时序逻辑仿真成组合逻辑?你知道原因吗?

    对于初学者 一般会遇到这种情况 明明写的时序逻辑 结果仿真结果却是组合逻辑 然后看遍设计代码 始终找不到原因 交流群 知乎这种问题随处可见 但不要怀疑软件问题 modelsim这些专用软件基本不会遇见软件自身问题 原因其实很简单 因为多数人