在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
12
返回列表 发新帖
楼主: 春野雪

[求助] 求助一个初级问题!!!

[复制链接]
 楼主| 发表于 2015-9-6 14:07:35 | 显示全部楼层
回复 9# tiancaijiameng


   您说的很对,不过我想知道的是“为什么异步复位,没有延迟?”,posedge是我发帖时写错了,negedge也是同样没有延迟,为什么???
 楼主| 发表于 2015-9-6 14:10:03 | 显示全部楼层
回复 7# haimo

没有吗?你试过了没有?这个posedge是我发帖时写错了,不好意思,是应该negedge。如果真是这个原因,编译都通不过,怎么可能仿真呢?这不是原因所在,negedge也是同样没有延迟。
发表于 2015-9-6 19:04:44 | 显示全部楼层
是比较奇怪:建议你把完整代码贴出来;你看看编译过程有没有提示什么warning;test bench也贴出来。
发表于 2015-9-6 19:44:42 | 显示全部楼层
个人理解异步复位是指你negedge i_rst_n(我知道你这里是写错了)的时候触发,而不是等到下一个posedge clk的时候触发

而你贴出来的时序图,是从已经是复位状态到正常工作的时候,这个过程就不存在同步异步了,这个时候全部是由posedge clk触发的动作


你应该比较i_rst_n从1到0的时候,那个地方同步异步的波形会有区别
发表于 2015-9-6 19:49:33 | 显示全部楼层
本帖最后由 acgoal 于 2015-9-6 22:24 编辑

回复 1# 春野雪


   我写了实际的例子来运行你的这段程序,用的是VCS仿真和编译工具。得到的结论是,其实这个是跟仿真器相关的,我用VCS仿真你这两端程序,其实得到的是同一个波形图,不过对于驱动端的阻塞和非阻塞赋值有写不一样的发现。下面我把我做的例子和大家分享一下。
   设计源代码如下:




  1. `timescale 1ns/1ps
  2. module counter (data_out0, data_out1,clk,rst_n, data_in0, data_in1);
  3. output [3:0] data_out0;
  4. output [3:0] data_out1;
  5. input [3:0] data_in0;
  6. input [3:0] data_in1;
  7. input clk;
  8. input rst_n;

  9. reg [3:0] data_out0;
  10. reg [3:0] data_out1;
  11. always @(posedge clk or negedge rst_n) begin
  12.   if(!rst_n) begin
  13.     data_out0 <= 4'd0;
  14.   end
  15.   else begin
  16.     data_out0 <= data_in0;
  17.   end
  18. end
  19. always @(posedge clk) begin
  20.   if(!rst_n) begin
  21.     data_out1 <= 4'd0;
  22.   end
  23.   else begin
  24.     data_out1 <= data_in1;
  25.   end
  26. end
  27. endmodule



复制代码



这里有两段,分别表示带异步复位和带同步复位的。

测试程序如下:




  1. `timescale 1ns/1ps
  2. module tb_top;
  3. reg clk;
  4. reg rst_n;
  5. wire [3:0] data_out0;
  6. wire [3:0] data_out1;
  7. reg [3:0] data_in0;
  8. reg [3:0] data_in1;
  9. 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));

  10. initial  begin
  11.   clk=1'b0;
  12. end
  13. always begin
  14.   #3 clk=~clk;
  15. end
  16. initial begin
  17.   rst_n = 1'b1;
  18.   #15 rst_n = 1'b0;
  19.   #180 rst_n = 1'b1;
  20.   #200 $finish;
  21. end

  22. [code]initial begin
  23. data_in0 <= 0;
  24. wait(!rst_n);
  25. wait(rst_n);
  26. @(posedge clk);
  27. data_in0 <= 1;
  28. @(posedge clk);
  29. data_in0 <= 2;
  30. @(posedge clk);
  31. data_in0 <= 4;
  32. @(posedge clk);
  33. data_in0 <= 8;
  34. @(posedge clk);
  35. data_in0 <= 0;
  36. end

  37. initial begin
  38. data_in1 <= 0;
  39. wait(!rst_n);
  40. wait(rst_n);
  41. @(posedge clk);
  42. data_in1 <= 1;
  43. @(posedge clk);
  44. data_in1 <= 2;
  45. @(posedge clk);
  46. data_in1 <= 4;
  47. @(posedge clk);
  48. data_in1 <= 8;
  49. @(posedge clk);
  50. data_in1 <= 0;
  51. end

  52. initial begin
  53.   $vcdpluson();
  54. end
  55. endmodule


复制代码



注意这里红色的部分,data0和data1的驱动都用非阻塞赋值。得到的仿真波形图如下:
非阻塞驱动.PNG



下面我把非阻塞赋值改成阻塞赋值,改动部分如下:





  1. initial begin
  2. data_in0 = 0;
  3. wait(!rst_n);
  4. wait(rst_n);
  5. @(posedge clk);
  6. data_in0 = 1;
  7. @(posedge clk);
  8. data_in0 = 2;
  9. @(posedge clk);
  10. data_in0 = 4;
  11. @(posedge clk);
  12. data_in0 = 8;
  13. @(posedge clk);
  14. data_in0 = 0;
  15. end

  16. initial begin
  17. data_in1 = 0;
  18. wait(!rst_n);
  19. wait(rst_n);
  20. @(posedge clk);
  21. data_in1 = 1;
  22. @(posedge clk);
  23. data_in1 = 2;
  24. @(posedge clk);
  25. data_in1 = 4;
  26. @(posedge clk);
  27. data_in1 = 8;
  28. @(posedge clk);
  29. data_in1 = 0;
  30. end



复制代码




这样的代码,仿真波形图如下:
阻塞赋值.PNG


和上面的不一样,为什么呢,为什么这次的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行为一致了(就是并行执行)。


结论:做驱动的接口信号最好是非阻塞赋值出去。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /1 下一条

X

小黑屋| 手机版| 关于我们| 联系我们| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2025-6-27 22:47 , Processed in 0.024647 second(s), 8 queries , Gzip On, MemCached On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表