为什么时序逻辑电路会落后一拍?

2024-01-26 11:12

本文主要是介绍为什么时序逻辑电路会落后一拍?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、时序逻辑电路落后一拍?

FPGA初学者可能经常听到一句话:“时序逻辑电路,或者说用 <= 输出的电路会延迟(落后)一个时钟周期。”但在仿真过程中经常会发现不符合这一“定律”的现象–明明是在仿真时序逻辑,怎么输出不会落后一拍?

先来看一个简单的例子:把输入信号用时序逻辑电路寄存两次,即俗称的“打两拍”。Verilog代码如下:

module test(  input 				clk,	//系统时钟;  input				rst,	//系统复位,高电平有效;  input		[1:0]	in,		 output		[1:0]	out 
);reg [1:0]	in_r,in_rr;		//分别打一拍、打两拍assign out = in_rr;always@(posedge clk or posedge rst)begin if(rst)begin in_r <= 2'd0;		//复位初始值in_rr <= 2'd0;		//复位初始值endelse beginin_r <= in;			//输入打一拍in_rr <= in_r;		//输入打两拍end
endendmodule

然后再写个TB文件来仿真一下:

`timescale 1 ns/1 ns  
module tb_test();  //输入输出端口
reg			clk;  
reg			rst;  
reg [1:0]	in;
wire [1:0]	out; //例化被测试模块	
test  u_test (  .clk	(clk),  .rst	(rst),  .in		(in	),   .out	(out)  
);  //生成系统时钟,周期10ns;  
initial begin clk = 1;  forever #5 clk = ~clk;  
end//生成复位信号
initial begin rst = 1;#25;  rst = 0;  
end //生成输入信号(测试激励)
initial beginin = 0; #30;repeat(8)begin			//循环8次;#10  in = in + 1; 	//输入递增1end  $stop;					//停止仿真
endendmodule

这段测试代码的测试逻辑是:在复位完成后,每10ns依次对输入信号in执行+1操作,观察打一拍信号in_r和打两拍信号in_rr的变化。来看下仿真结果:
在这里插入图片描述

  • 输入信号in在每个时钟上升沿递增1,符合预期
  • 信号in_r原本应该落后信号in一个时钟周期,但上图中二者却完全同步,不符合预期!
  • 信号in_rr落后信号in_r一个时钟周期,符合预期

那么,是什么导致仿真结果与预期目的不符?

2、建立时间、保持时间和数据输出延迟

在FPGA设计中所用的底层时序逻辑单元是D触发器(DFF,D Flip-Flop),在理想状况下,可以认为DFF的变化是瞬态的,即输出从0到1或者从1到0,都是在一瞬间完成。但在实际使用中,这种瞬态变化显然不可能存在,所以寄存器的输出必定需要一些时间,而这个时间就是Tco。
在这里插入图片描述
上图是一张DFF的非理想状态下的数据传输示意图,为此需要明确3个概念:

  • Tsu:D端的数据必须在时钟上升沿到来之前的一定时间内就已经保持稳定,该时间被称为D触发器的建立时间(Tsu)。
  • Th:D端的数据必须在时钟上升沿到来之后的一定时间内继续保持稳定,该时间被称为D触发器的保持时间(Th)。
  • Tco:D端的数据不可能会在时钟上升沿出现的那一刻就立即更新到Q端,从时钟的上升沿到D端的数据稳定出现在Q端,也有一个时间,该时间称为寄存器的时钟到输出延迟(Tco)。

上面的概念理解两点即可:

  1. 如果不满足建立时间和保持时间要求,则DFF的输出可能会出现亚稳态,简单理解就是输出容易不正常,会出问题。
  2. 每个时钟上升沿(或下降沿)DFF都会从输入端采集数据并将其更新到输出端,但这个过程需要时间(Tco),所以数据的输出实际上会落后时钟上升沿一些时间。

3、时序逻辑电路落后一个周期的原因

接下来继续分析上面的仿真结果。
在这里插入图片描述

  • 在①处,信号in_r在发生变化,由于Tco的存在,所以in_r从0到1的时间是不会和上升沿同步的,会落后一点点。仿真波形表示的不是很明显,但也用了一个小小的斜坡来表示这一过程。
  • 在①处,信号in_r的变化会落后于上升沿,信号in_rr在①处采集到的值则仍是信号in_r未变化的值,即0。
  • 在②处,信号in_r的变化同上一个时钟①处类似。信号in_r的变化会落后于上升沿,信号in_rr在②处采集到的值则仍是信号in_r未变化的值,即1。

这样理解起来可能还是不够直观,没事,我们把代码做一些小小的改变:

in_r <= #1 in;			//输入打一拍
in_rr <= #1 in_r;		//输入打两拍

只是把输出语句加一个 “#1”,即输出会延迟1ns。聪明的你应该已经看出来了,这就是用来模拟Tco这个概念的。

在这里插入图片描述

继续看仿真结果,是不是一目了然?

  • 在①处,由于Tco的存在,所以in_rr采集到的in_r的值是0,所以in_rr输出也是0,而且输出会落后一个Tco时间(但是由于值相同,所以看不出来)
  • 在②处,由于Tco的存在,所以in_rr采集到的in_r的值是1,所以in_rr输出也是1,而且输出也会落后一个Tco时间

所以现在我们清楚了,时序逻辑电路的输出根本就不会落后一个时钟周期,而只会落后一个Tco时间。二者之所以看上去会落后一个周期,完全是由于前级输出的Tco时间存在,导致后级电路在当前时钟上升沿无法采集到最新值,而只能采集到前级未变化的值!

4、为什么把时序逻辑仿成了组合逻辑?

上面的仿真还有个问题悬而未决,那就是in_r是in被寄存后的信号,为啥没有落后in一个时钟周期?问题出在仿真机制和TB文件中对in的赋值方式上。

在TB中,我们是这么对in赋值的:

#10 in = in + 1; //输入递增1

注意看,用的是阻塞赋值“ = ”,阻塞赋值“ = ”一般用来描述组合逻辑,而非阻塞赋值“ <= "则一般用来描述时序逻辑。

虽然输入信号in是我们构建的一个虚拟向量,但对于被测试模块来说,这个激励仍然被视作是来自于上级模块的输出,所以需要指明它到底是一个组合逻辑的输出值还是一个时序逻辑的输出值。

如果它是用“ = ”来描述的,那它就是来自组合逻辑,而组合逻辑的输出是不与时钟上升沿有关的,它的输出几乎就是瞬时完成的。如果它是用“ <= ”来描述的,那它就是来自时序逻辑,而时序逻辑的输出则会落后时钟上升沿一个Tco时间。

回到上面的仿真结果,由于信号in使用“ = ”来赋值,所以它的每一次更新都几乎与时钟上升沿同步,并不会有Tco时间的存在,每一个上升沿后级的in_r信号都能采集到最新的in值,所以二者并不会有一个周期的延迟。

假如我们把信号in改成“ <= ”这种赋值方式:

#10 in <= in + 1; //输入递增1

那么仿真结果就是这样了:
在这里插入图片描述

这与我们最初料想的一致:打一拍信号in_r落后输入信号in一个时钟周期,打两拍信号in_rr后输入信号两个时钟周期。

如果说还有问题的话,就是输入信号in的变化没有很好的体现Tco时间,所以再修改一下:

#10 in <= #1 in + 1; //输入递增1

在这里插入图片描述

嗯,这样就没问题了。由于采用了“#1”这种赋值方式来模拟Tco的存在,所以你应该再也不会搞错信号在哪个时钟沿采样和哪个时钟沿变化了。

5、总结

  • 时序逻辑电路的输出不是瞬时发生的,而是需要一定的时间,这个时间就是Tco
  • 时序逻辑电路并没有真正意义上的落后一拍,落后一拍的原因是因为Tco的存在,导致在当前时钟上升沿无法采集到最新的值,而只能采集到未变化的值
  • 在仿真时,输入信号尽量用非阻塞赋值“<=”来模拟其来自寄存器的输出,这样的仿真结果更接近实际电路
  • 可以采用“#1”这种赋值方式来模拟Tco的存在,这可以在仿真时带来很大的便利

  • 📣您有任何问题,都可以在评论区和我交流📃!
  • 📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
  • 📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐

这篇关于为什么时序逻辑电路会落后一拍?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

22.手绘Spring DI运行时序图

1.依赖注入发生的时间 当Spring loC容器完成了 Bean定义资源的定位、载入和解析注册以后,loC容器中已经管理类Bean 定义的相关数据,但是此时loC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况 发生: 、用户第一次调用getBean()方法时,loC容器触发依赖注入。 、当用户在配置文件中将<bean>元素配置了 lazy-init二false属性,即让

21.手绘Spring IOC运行时序图

1.再谈IOC与 DI IOC(lnversion of Control)控制反转:所谓控制反转,就是把原先我们代码里面需要实现的对象创 建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让 容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们所看到的配置文件。 DI(Dependency Injection)依赖注入:就是指对象是被动接受依赖类

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

FPGA静态时序分析工具

1.Xilinx FPGA 使用Vivado 2.Altera FPGA 使用Quartus 3.Actel FPGA 使用Libero 4.Lattice FPGA使用Diamond 5.Synopsys 公司的Prime Time 6.Cadence 公司的Pearl

QuantML-Qlib Model | Kansformer: KAN+Transformer时序模型用于股票收益率预测

QuantML-Qlib Model | Kansformer: KAN+Transformer时序模型用于股票收益率预测 原创 QuantML QuantML 2024-06-18 20:57 上海 Content 之前公众号介绍了几篇KAN的文章,也做过KAN相关的模型: What KAN I say?KAN代码全解析 QuantML-Qlib开发版 | 最新神经网络结构KAN用于因

深度学习算法informer(时序预测)(三)(Encoder)

一、EncoderLayer架构如图(不改变输入形状) 二、ConvLayer架构如图(输入形状中特征维度减半)  三、Encoder整体 包括三部分 1. 多层EncoderLayer 2. 多层ConvLayer 3. 层归一化 代码如下 class AttentionLayer(nn.Module):def __init__(self, attention, d_mo

全网最易懂,开源时序数据库influxDB,实际应用评测

前言:         当今是信息爆炸的时代,在处理高频数据时,关系型数据库oracle/mysql明显表现出乏力,因秒级、毫秒级高频数据,分分钟可以把关系型数据库的表塞爆。在日常生活工作中,我们经常会遇到哪些需要高频分析的场景呢?本次我们借鉴时序数据库influxDB来引出高频数据分析的实践方案。 一、场景引导选型         1、高频数据场景         首先来说说我接触到的高

深度学习算法informer(时序预测)(四)(Decoder)

一、DecoderLayer架构如图(不改变输入形状)    二、Decoder整体 包括两部分 1. 多层DecoderLayer 2. 层归一化 代码如下 class DecoderLayer(nn.Module):def __init__(self, self_attention, cross_attention, d_model, d_ff=None,dropout=0.

【时序预测】-Transformer系列

Transformer 2017 NIPS 重点:Attention Is All You Need 核心:Attention Is All You Need Informer 2021 AAAI(Best Paper) 重点:Transformer + Sparse attention (稀疏) 核心:Sparse attention(ProbSparse attention)结构:只

Apache Druid-时序数据库

Apache Druid:是是一个集时间序列数据库、数据仓库和全文检索系统特点于一体的分析性数据平台,旨在对大型数据集进行快速的查询分析("OLAP"查询)。Druid最常被当做数据库来用以支持实时摄取、高性能查询和高稳定运行的应用场景,同时,Druid也通常被用来助力分析型应用的图形化界面,或者当做需要快速聚合的高并发后端API,Druid最适合应用于面向事件类型的数据。特性 实时数据摄取:Dr