AXI_BVALID/AXI_BREADY的异步处理

AXI_BVALID/AXI_BREADY的异步处理

AXI_BVALID/AXI_BREADY的异步处理本质上是单比特信号的异步处理,但其对持续总cycle数也需要保持一致。并且需要考虑到VALID/READY的握手关系。

思路是用一个计数器对源时钟域的A_AXI_BVALID&A_AXI_BREADY做计数,然后转换成格雷码,再同步到目标时钟域去,再转换成顺序计数码,在目标时钟域根据B_AXI_BREADY生成对应的B_AXI_BVALID。同时需要注意把目标时钟域的计数器反过来同步到源时钟域,判断存储的bvalid个数即将满的时候把A_AXI_BREADY拉低,需要预留一定的反向同步时间。

以下是RTL代码:

module bvalid_sync(

input  a_axi_rstn,
input  a_axi_clk,
input  a_axi_bvalid,
output a_axi_bready,

input  b_axi_rstn,
input  b_axi_clk,
input  b_axi_bready,
output b_axi_bvalid
);

reg [3:0] cnt_a_axi_bvalid;
always @ (posedge a_axi_clk)
begin
  if (a_axi_rstn == 0)
    cnt_a_axi_bvalid <= 'd0;
  else if (a_axi_bvalid & a_axi_bready)
    cnt_a_axi_bvalid <= cnt_a_axi_bvalid + 'd1;
end

function [3:0] bin2gray; 
input [3:0] data_bin;
begin
bin2gray[3] = data_bin[3];
bin2gray[2] = data_bin[3]^data_bin[2];
bin2gray[1] = data_bin[2]^data_bin[1];
bin2gray[0] = data_bin[1]^data_bin[0];
end
endfunction

reg [3:0] gcnt_a_bvalid_sync0;
reg [3:0] gcnt_a_bvalid_sync1;

always @ (posedge b_axi_clk)
begin
  if (b_axi_rstn == 0) begin
    gcnt_a_bvalid_sync0 <= 'd0;
    gcnt_a_bvalid_sync1 <= 'd0;
  end
  else begin
    gcnt_a_bvalid_sync0 <= bin2gray(cnt_a_axi_bvalid);
    gcnt_a_bvalid_sync1 <= gcnt_a_bvalid_sync0;
  end
end

function [3:0] gray2bin; 
input [3:0] data_gray;
begin
gray2bin[3] = data_gray[3];
gray2bin[2] = gray2bin[3]^data_gray[2];
gray2bin[1] = gray2bin[2]^data_gray[1];
gray2bin[0] = gray2bin[1]^data_gray[0];
end
endfunction

wire [3:0] cnt_a_bvalid_sync = gray2bin(gcnt_a_bvalid_sync1);

reg [3:0] cnt_b_axi_bvalid;

always @ (posedge b_axi_clk)
begin
  if (b_axi_rstn == 0)
    cnt_b_axi_bvalid <= 'd0;
  else if (b_axi_bvalid)
    cnt_b_axi_bvalid <= cnt_b_axi_bvalid + 'd1;
end

wire fifo_empty = (cnt_b_axi_bvalid == cnt_a_bvalid_sync);

assign b_axi_bvalid = b_axi_bready & ~fifo_empty;

reg [3:0] gcnt_b_bvalid_sync0;
reg [3:0] gcnt_b_bvalid_sync1;
always @ (posedge a_axi_clk)
begin
  if (a_axi_rstn == 0) begin
    gcnt_b_bvalid_sync0 <= 'd0;
    gcnt_b_bvalid_sync1 <= 'd0;
  end
  else begin
    gcnt_b_bvalid_sync0 <= bin2gray(cnt_b_axi_bvalid);
    gcnt_b_bvalid_sync1 <= gcnt_b_bvalid_sync0;
  end
end

wire [3:0] cnt_b_bvalid_sync = gray2bin(gcnt_b_bvalid_sync1);

wire [3:0] cnt_a_axi_bvalid_add = cnt_a_axi_bvalid + 4;

wire fifo_full = (cnt_a_axi_bvalid_add[3]^cnt_b_bvalid_sync[3])&(cnt_a_axi_bvalid_add[2:0] == cnt_b_bvalid_sync[2:0]);

assign a_axi_bready = ~fifo_full;

endmodule

Testbench:

module tb_bvalid_sync ;
    
reg  a_axi_rstn    ;
reg  a_axi_clk     ;
reg  a_axi_bvalid  ;
wire a_axi_bready  ;

reg      b_axi_clk   ;
reg      b_axi_rstn  ; 
reg      b_axi_bready;
wire     b_axi_bvalid ;
    
    
parameter A_PERIOD = 23;
parameter B_PERIOD = 20;
    
always #(A_PERIOD/2) a_axi_clk = ~a_axi_clk;
always #(B_PERIOD/2) b_axi_clk = ~b_axi_clk; 
always #(B_PERIOD*20) b_axi_bready = ~b_axi_bready; 

initial begin
a_axi_rstn   = 0;
a_axi_clk    = 0;
a_axi_bvalid = 0;

b_axi_clk    = 0;
b_axi_rstn   = 0;
b_axi_bready = 0;

#100;
a_axi_rstn = 1;
b_axi_rstn = 1;
#100;
a_axi_bvalid = 1;
#10000;
a_axi_bvalid = 0;
#1000;
$stop;
end

reg [31:0] cnt_a;
always @ (posedge a_axi_clk)
begin
  if (a_axi_rstn == 0)
    cnt_a <= 'd0;
  else if (a_axi_bvalid & a_axi_bready)
    cnt_a <= cnt_a + 'd1;
end

reg [31:0] cnt_b;
always @ (posedge b_axi_clk)
begin
  if (b_axi_rstn == 0)
    cnt_b <= 'd0;
  else if (b_axi_bvalid & b_axi_bready)
    cnt_b <= cnt_b + 'd1;
end

bvalid_sync u_bvalid_sync(

 .a_axi_rstn   (a_axi_rstn  ),
 .a_axi_clk    (a_axi_clk   ),
 .a_axi_bvalid (a_axi_bvalid),
 .a_axi_bready (a_axi_bready),
 
 .b_axi_clk    (b_axi_clk   ),
 .b_axi_rstn   (b_axi_rstn  ),
 .b_axi_bready (b_axi_bready),
 .b_axi_bvalid  (b_axi_bvalid )
);

endmodule

经测试,A_PERIOD = 0.1~10 B_PERIOD 都是正确的。
正确的判断条件是:仿真结束后,testbench里面的 cnt_a == cnt_b;

你可能感兴趣的:(FPGA)