当前位置:   article > 正文

多比特跨时钟域之握手及DMUX

多比特跨时钟域之握手及DMUX

一、握手toggle

握手又称结绳法,适用场景为数据有效信号在数据信号前一个周期或数据有效信号在数据的第一个周期,且在握手期间,数据需要保持不变,直到源时钟域收到了解绳的有效信号。

源码如下:

  1. module toggle(
  2. input wire clka,
  3. input wire clkb,
  4. input wire rst_n,
  5. input wire a_en,
  6. input wire [7:0] data_a_in,
  7. output reg [7:0] data_b_out,
  8. output wire b_en,
  9. output wire ack_a
  10. );
  11. reg a_en_d1;
  12. reg a_en_d2;
  13. wire a_en_neg;
  14. reg a_req;
  15. reg req_d1;
  16. reg req_d2;
  17. reg ack_d1;
  18. reg ack_d2;
  19. wire ack_pos;
  20. always@(posedge clka or negedge rst_n)begin
  21. if(!rst_n)begin
  22. a_en_d1 <= 1'b0;
  23. a_en_d2 <= 1'b0;
  24. end
  25. else begin
  26. a_en_d1 <= a_en;
  27. a_en_d2 <= a_en_d1;
  28. end
  29. end
  30. assign a_en_neg = a_en_d2 && (~a_en_d1);
  31. always@(posedge clka or negedge rst_n)begin
  32. if(!rst_n)
  33. a_req <= 1'b0;
  34. else if(a_en_neg)
  35. a_req <= 1'b1;
  36. else if(ack_pos)
  37. a_req <= 1'b0;
  38. end
  39. always@(posedge clkb or negedge rst_n)begin
  40. if(!rst_n)begin
  41. req_d1 <= 1'b0;
  42. req_d2 <= 1'b0;
  43. end
  44. else begin
  45. req_d1 <= a_req;
  46. req_d2 <= req_d1;
  47. end
  48. end
  49. always@(posedge clka or negedge rst_n)begin
  50. if(!rst_n)begin
  51. ack_d1 <= 1'b0;
  52. ack_d2 <= 1'b0;
  53. end
  54. else begin
  55. ack_d1 <= req_d2;
  56. ack_d2 <= ack_d1;
  57. end
  58. end
  59. assign b_en = (~req_d2) && (req_d1);
  60. assign ack_pos = (~ack_d2) && ack_d1;
  61. assign ack_a = ack_d2;
  62. always@(posedge clkb or negedge rst_n)begin
  63. if(!rst_n)
  64. data_b_out <= 8'd0;
  65. else if(b_en)
  66. data_b_out <= data_a_in;
  67. end
  68. endmodule

testbench如下:

  1. `timescale 1ns/1ns
  2. module toggle_tb();
  3. reg clka;
  4. reg clkb;
  5. reg rst_n;
  6. reg a_en;
  7. reg [7:0] data_a_in;
  8. wire [7:0] data_b_out;
  9. wire b_en;
  10. wire ack_a;
  11. always #5 clka = ~clka;
  12. always #10 clkb = ~clkb;
  13. initial begin
  14. rst_n = 1'b0;
  15. clka = 1'b0;
  16. clkb = 1'b0;
  17. #11;
  18. rst_n = 1'b1;
  19. #10000;
  20. $finish;
  21. end
  22. reg ack_a_d1;
  23. always@(posedge clka or negedge rst_n)begin
  24. if(!rst_n)begin
  25. a_en <= 1'b1;
  26. ack_a_d1 <= 1'b0;
  27. end
  28. else begin
  29. ack_a_d1 <= ack_a;
  30. a_en <= (~ack_a_d1) && ack_a;
  31. end
  32. end
  33. always@(posedge clka or negedge rst_n)begin
  34. if(!rst_n)
  35. data_a_in <= 8'd0;
  36. else if(a_en)
  37. data_a_in <= {$random}%256;
  38. end
  39. toggle toggle_inst(
  40. .clka (clka),
  41. .clkb (clkb),
  42. .rst_n (rst_n),
  43. .a_en (a_en),
  44. .data_a_in (data_a_in),
  45. .data_b_out (data_b_out),
  46. .b_en (b_en),
  47. .ack_a (ack_a)
  48. );
  49. initial begin
  50. $fsdbDumpfile("tb.fsdb");
  51. $fsdbDumpvars;
  52. end
  53. endmodule

仿真结果如下:

其中G1中为源时钟域信号,G2为目的时钟域信号

二,DMUX

 原理图如下:

DMUX适用于慢时钟域向快时钟域传递(因为两级同步器),且数据有效信号在数据信号的前一个周期或者数据有效信号在数据信号的第一个周期。数据信号要保证在有效信号同步期间保持不变。

源代码如下:

  1. module dmux(
  2. input wire clka,
  3. input wire clkb,
  4. input wire a_en,
  5. input wire rst_n,
  6. input wire [7:0] data_in,
  7. output reg [7:0] data_out
  8. );
  9. reg a_en_d1;
  10. reg a_en_d2;
  11. always@(posedge clkb or negedge rst_n)begin
  12. if(!rst_n)begin
  13. a_en_d1 <= 1'b0;
  14. a_en_d2 <= 1'b0;
  15. end
  16. else begin
  17. a_en_d1 <= a_en;
  18. a_en_d2 <= a_en_d1;
  19. end
  20. end
  21. always@(posedge clkb or negedge rst_n)begin
  22. if(!rst_n)
  23. data_out <= 8'd0;
  24. else if(a_en_d2)
  25. data_out <= data_in;
  26. end
  27. endmodule

testbench如下:

  1. `timescale 1ns/1ns;
  2. module dmux_tb();
  3. reg clka;
  4. reg clkb;
  5. reg rst_n;
  6. reg a_en;
  7. reg [7:0] data_in;
  8. wire [7:0] data_out;
  9. always #10 clka = ~clka;
  10. always #5 clkb = ~clkb;
  11. initial begin
  12. clka = 1'b0;
  13. clkb = 1'b0;
  14. rst_n = 1'b0;
  15. a_en = 1'b0;
  16. data_in = 8'd0;
  17. #11;
  18. rst_n = 1'b1;
  19. @(posedge clka)
  20. a_en = 1'b1;
  21. data_in = {$random} %256;
  22. @(posedge clka)
  23. a_en = 1'b0;
  24. #33;
  25. @(posedge clka)
  26. a_en = 1'b1;
  27. @(posedge clka)
  28. a_en = 1'b0;
  29. data_in = ($random)%256;
  30. #100;
  31. $finish;
  32. end
  33. dmux dmux_inst(
  34. .clka (clka),
  35. .clkb (clkb),
  36. .rst_n (rst_n),
  37. .a_en (a_en),
  38. .data_in (data_in),
  39. .data_out (data_out)
  40. );
  41. initial begin
  42. $fsdbDumpfile("tb.fsdb");
  43. $fsdbDumpvars;
  44. end
  45. endmodule

仿真结果如下:

可以清晰看到两种情况。

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/839145
推荐阅读
相关标签
  

闽ICP备14008679号