求助一个初级问题!

为什么异步复位,没有延迟一个时钟周期?求助,谢谢!
顶6666666
应该是negedge i_rst_n
感觉这个已经跟复位没关系了,上面是非阻塞赋值,下面却变成阻塞式赋值了(波形),看看是不是仿真的原因
是非阻塞赋值,你可以试一下,谢谢!
不知道你这个综合过了没有,复位信号确实没有匹配上,上升沿触发异步复位但是内部逻辑却是低电平复位,这里是有矛盾的。但是为什么会产生阻塞式赋值的现象,这个还请其他大神解释。
如果改为negedge i_rst_n就没有这个问题了。
你明明是低电平复位,为什么要写posedge?
异步复位应用的i_rst_n是FPGA寄存器自带的异步清零端(CLR),它不会占用FPGA的内部资源消耗;而同步复位是将i_rst_n作为输入逻辑使能信号,会增加FPGA内部资源消耗,FPGA运行时会先进行这个信号的判断,所以会有一个时钟的延迟。下面的是同步复位

复位是没匹配上,不好意思是我写错了,但是这不是原因所在,negedge i_rst_n也是一样的。
您说的很对,不过我想知道的是“为什么异步复位,没有延迟?”,posedge是我发帖时写错了,negedge也是同样没有延迟,为什么?
没有吗?你试过了没有?这个posedge是我发帖时写错了,不好意思,是应该negedge。如果真是这个原因,编译都通不过,怎么可能仿真呢?这不是原因所在,negedge也是同样没有延迟。
是比较奇怪:建议你把完整代码贴出来;你看看编译过程有没有提示什么warning;test bench也贴出来。
个人理解异步复位是指你negedge i_rst_n(我知道你这里是写错了)的时候触发,而不是等到下一个posedge clk的时候触发
而你贴出来的时序图,是从已经是复位状态到正常工作的时候,这个过程就不存在同步异步了,这个时候全部是由posedge clk触发的动作
你应该比较i_rst_n从1到0的时候,那个地方同步异步的波形会有区别
我写了实际的例子来运行你的这段程序,用的是VCS仿真和编译工具。得到的结论是,其实这个是跟仿真器相关的,我用VCS仿真你这两端程序,其实得到的是同一个波形图,不过对于驱动端的阻塞和非阻塞赋值有写不一样的发现。下面我把我做的例子和大家分享一下。
设计源代码如下:
- `timescale 1ns/1ps
- module counter (data_out0, data_out1,clk,rst_n, data_in0, data_in1);
- output [3:0] data_out0;
- output [3:0] data_out1;
- input [3:0] data_in0;
- input [3:0] data_in1;
- input clk;
- input rst_n;
- reg [3:0] data_out0;
- reg [3:0] data_out1;
- always @(posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- data_out0 <= 4'd0;
- end
- else begin
- data_out0 <= data_in0;
- end
- end
- always @(posedge clk) begin
- if(!rst_n) begin
- data_out1 <= 4'd0;
- end
- else begin
- data_out1 <= data_in1;
- end
- end
- endmodule
这里有两段,分别表示带异步复位和带同步复位的。
测试程序如下:
- `timescale 1ns/1ps
- module tb_top;
- reg clk;
- reg rst_n;
- wire [3:0] data_out0;
- wire [3:0] data_out1;
- reg [3:0] data_in0;
- reg [3:0] data_in1;
- counter u_counter0(.clk(clk), .rst_n(rst_n), .data_out0(data_out0), .data_out1(data_out1), .data_in0(data_in0), .data_in1(data_in1));
- initial begin
- clk=1'b0;
- end
- always begin
- #3 clk=~clk;
- end
- initial begin
- rst_n = 1'b1;
- #15 rst_n = 1'b0;
- #180 rst_n = 1'b1;
- #200 $finish;
- end
- [code]initial begin
- data_in0 <= 0;
- wait(!rst_n);
- wait(rst_n);
- @(posedge clk);
- data_in0 <= 1;
- @(posedge clk);
- data_in0 <= 2;
- @(posedge clk);
- data_in0 <= 4;
- @(posedge clk);
- data_in0 <= 8;
- @(posedge clk);
- data_in0 <= 0;
- end
- initial begin
- data_in1 <= 0;
- wait(!rst_n);
- wait(rst_n);
- @(posedge clk);
- data_in1 <= 1;
- @(posedge clk);
- data_in1 <= 2;
- @(posedge clk);
- data_in1 <= 4;
- @(posedge clk);
- data_in1 <= 8;
- @(posedge clk);
- data_in1 <= 0;
- end
- initial begin
- $vcdpluson();
- end
- endmodule
注意这里红色的部分,data0和data1的驱动都用非阻塞赋值。得到的仿真波形图如下:

下面我把非阻塞赋值改成阻塞赋值,改动部分如下:
- initial begin
- data_in0 = 0;
- wait(!rst_n);
- wait(rst_n);
- @(posedge clk);
- data_in0 = 1;
- @(posedge clk);
- data_in0 = 2;
- @(posedge clk);
- data_in0 = 4;
- @(posedge clk);
- data_in0 = 8;
- @(posedge clk);
- data_in0 = 0;
- end
- initial begin
- data_in1 = 0;
- wait(!rst_n);
- wait(rst_n);
- @(posedge clk);
- data_in1 = 1;
- @(posedge clk);
- data_in1 = 2;
- @(posedge clk);
- data_in1 = 4;
- @(posedge clk);
- data_in1 = 8;
- @(posedge clk);
- data_in1 = 0;
- end
这样的代码,仿真波形图如下:

和上面的不一样,为什么呢,为什么这次的flop行为没有了呢?直接给结论吧。
根据verilog/system verilog的standard。我这里以system verilog的standard为例,STD 1800-2009版本,第四章“Scheduling Semantics”,这一章关于仿真的调度描述。
simulation的event大体分为:Active event -> Inactive event -> NBA event -> Overserved event -> Reactive -> Re-Inactive -> Re-NBA
一般的,阻塞赋值发生在active/inactive event,而NBA( Non-blocking assignment update)从字面意思就能看出来是做非阻塞赋值的。
再结合上面的例子,如果data_in0是阻塞赋值出去的话,因为例子里的dut是在时钟上升延来的时候进行非阻塞赋值(data_out0 <= data_in0),这句话属于NBA event,而阻塞赋值data_in0 = 1 (或者2,4,8)是Active event,他比NBA要先执行,所以我们看到data_out0在当前的cycle就被采样到了。这就是后面一个波形图的样子,看起来就像flop没有用一样。实际上是我们driver写的有问题。
如果data_in0在testbench里面用阻塞赋值就是 data_in0 <= 1 (或者2,4,8,见例子),那么data_out0 <= data_in0, 和data_in0 <= 1同属于NBA event。这样子这两句话同时执行,这样就和实际电路中的flop行为一致了(就是并行执行)。
结论:做驱动的接口信号最好是非阻塞赋值出去。
