网站开发用什么,开一家网站建设公司要多少钱,wordpress调用文件,深圳 营销型网站建设1、时序逻辑电路落后一拍#xff1f;
FPGA初学者可能经常听到一句话#xff1a;“时序逻辑电路#xff0c;或者说用 输出的电路会延迟#xff08;落后#xff09;一个时钟周期。”但在仿真过程中经常会发现不符合这一“定律”的现象–明明是在仿真时序逻辑#xff…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 2d0; //复位初始值in_rr 2d0; //复位初始值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触发器DFFD Flip-Flop在理想状况下可以认为DFF的变化是瞬态的即输出从0到1或者从1到0都是在一瞬间完成。但在实际使用中这种瞬态变化显然不可能存在所以寄存器的输出必定需要一些时间而这个时间就是Tco。 上图是一张DFF的非理想状态下的数据传输示意图为此需要明确3个概念
TsuD端的数据必须在时钟上升沿到来之前的一定时间内就已经保持稳定该时间被称为D触发器的建立时间Tsu。ThD端的数据必须在时钟上升沿到来之后的一定时间内继续保持稳定该时间被称为D触发器的保持时间Th。TcoD端的数据不可能会在时钟上升沿出现的那一刻就立即更新到Q端从时钟的上升沿到D端的数据稳定出现在Q端也有一个时间该时间称为寄存器的时钟到输出延迟Tco。
上面的概念理解两点即可
如果不满足建立时间和保持时间要求则DFF的输出可能会出现亚稳态简单理解就是输出容易不正常会出问题。每个时钟上升沿或下降沿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您的支持是我持续创作的最大动力如果本文对您有帮助还请多多点赞、评论和收藏⭐