axi_dacfifo: Optimize the AXI read logic

Save the valid AXI beats number of the last AXI transaction, and the valid
DMA beats number of the last AXI beat, so the read back logic can use this
data and prevent to feel up the CDC memory with invalid samples. Also in
this way the end of the read back cycle get a more robust control: no more
duplicated samples at the end of the buffer.
main
Istvan Csomortani 2016-07-20 11:27:06 +03:00
parent e46990e508
commit b9a5bb3549
4 changed files with 145 additions and 70 deletions

View File

@ -200,7 +200,9 @@ module axi_dacfifo (
wire dac_rd_ready_s;
wire dac_rd_valid_s;
wire [31:0] axi_last_addr_s;
wire [31:0] dma_last_addr_s;
wire [ 3:0] axi_last_beats_s;
wire axi_dlast_s;
wire [ 3:0] dma_last_beats_s;
wire [(DAC_DATA_WIDTH-1):0] dac_data_s;
wire dma_ready_s;
wire dma_valid_bp_s;
@ -221,8 +223,9 @@ module axi_dacfifo (
.dma_valid (dma_valid),
.dma_xfer_req (dma_xfer_req),
.dma_xfer_last (dma_xfer_last),
.dma_last_beats (dma_last_beats_s),
.axi_last_addr (axi_last_addr_s),
.dma_last_addr (dma_last_addr_s),
.axi_last_beats (axi_last_beats_s),
.axi_xfer_out (axi_xfer_req_s),
.axi_clk (axi_clk),
.axi_resetn (axi_resetn),
@ -257,8 +260,9 @@ module axi_dacfifo (
.AXI_LENGTH (AXI_LENGTH),
.AXI_ADDRESS (AXI_ADDRESS)
) i_rd (
.axi_last_raddr (axi_last_addr_s),
.axi_xfer_req (axi_xfer_req_s),
.axi_last_raddr (axi_last_addr_s),
.axi_last_beats (axi_last_beats_s),
.axi_clk (axi_clk),
.axi_resetn (axi_resetn),
.axi_arvalid (axi_arvalid),
@ -283,7 +287,8 @@ module axi_dacfifo (
.axi_rerror (axi_rerror),
.axi_dvalid (axi_rd_valid_s),
.axi_ddata (axi_rd_data_s),
.axi_dready (axi_rd_ready_s));
.axi_dready (axi_rd_ready_s),
.axi_dlast (axi_dlast_s));
axi_dacfifo_dac #(
.AXI_DATA_WIDTH (AXI_DATA_WIDTH),
@ -294,8 +299,9 @@ module axi_dacfifo (
.axi_dvalid (dac_rd_valid_s),
.axi_ddata (dac_rd_data_s),
.axi_dready (axi_rd_ready_s),
.axi_dlast (axi_dlast_s),
.axi_xfer_req (axi_xfer_req_s),
.dma_last_addr (dma_last_addr_s),
.dma_last_beats (dma_last_beats_s),
.dac_clk (dac_clk),
.dac_rst (dac_rst),
.dac_valid (dac_valid),

View File

@ -45,9 +45,10 @@ module axi_dacfifo_dac (
axi_dvalid,
axi_ddata,
axi_dready,
axi_dlast,
axi_xfer_req,
dma_last_addr,
dma_last_beats,
dac_clk,
dac_rst,
@ -84,9 +85,10 @@ module axi_dacfifo_dac (
input axi_dvalid;
input [(AXI_DATA_WIDTH-1):0] axi_ddata;
output axi_dready;
input axi_dlast;
input axi_xfer_req;
input [31:0] dma_last_addr;
input [ 3:0] dma_last_beats;
// dac read
@ -100,7 +102,9 @@ module axi_dacfifo_dac (
// internal registers
reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'd0;
reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_laddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_waddr_g = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_laddr_g = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr_m1 = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr_m2 = 'd0;
@ -108,11 +112,13 @@ module axi_dacfifo_dac (
reg axi_dready = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_raddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_raddr_next = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_raddr_g = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_waddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_waddr_m1 = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_waddr_m2 = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_laddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_laddr_m1 = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_laddr_m2 = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_addr_diff = 'd0;
reg dac_mem_init = 1'b0;
reg dac_mem_init_d = 1'b0;
@ -121,24 +127,26 @@ module axi_dacfifo_dac (
reg [ 2:0] dac_xfer_req_m = 3'b0;
reg dac_xfer_init = 1'b0;
reg [31:0] dac_raddr_cnt = 32'b0;
reg [31:0] dac_last_raddr = 32'b0;
reg [31:0] dac_last_raddr_m = 32'b0;
reg dac_almost_full = 1'b0;
reg dac_almost_empty = 1'b0;
reg [ 3:0] dac_last_beats = 4'b0;
reg [ 3:0] dac_last_beats_m = 4'b0;
reg dac_dunf = 1'b0;
reg [ 3:0] dac_beat_cnt = 4'b0;
reg dac_dlast = 1'b0;
reg dac_dlast_m1 = 1'b0;
reg dac_dlast_m2 = 1'b0;
reg dac_dlast_inmem = 1'b0;
// internal signals
wire [AXI_ADDRESS_WIDTH:0] axi_mem_addr_diff_s;
wire [(AXI_ADDRESS_WIDTH-1):0] axi_mem_raddr_s;
wire [(DAC_ADDRESS_WIDTH-1):0] axi_mem_waddr_s;
wire [(DAC_ADDRESS_WIDTH-1):0] axi_mem_laddr_s;
wire [DAC_ADDRESS_WIDTH:0] dac_mem_addr_diff_s;
wire [DAC_ADDRESS_WIDTH:0] dac_mem_raddr_diff_s;
wire [(DAC_ADDRESS_WIDTH-1):0] dac_mem_waddr_s;
wire dac_mem_valid_s;
wire dac_xfer_init_s;
wire dac_last_axi_beats_s;
// binary to grey conversion
@ -186,11 +194,14 @@ module axi_dacfifo_dac (
if (axi_xfer_req == 1'b0) begin
axi_mem_waddr <= 'd0;
axi_mem_waddr_g <= 'd0;
axi_mem_laddr <= {AXI_ADDRESS_WIDTH{1'b1}};
end else begin
if (axi_dvalid == 1'b1) begin
axi_mem_waddr <= axi_mem_waddr + 1'b1;
axi_mem_laddr <= (axi_dlast == 1'b1) ? axi_mem_waddr : axi_mem_laddr;
end
axi_mem_waddr_g <= b2g(axi_mem_waddr_s);
axi_mem_laddr_g <= b2g(axi_mem_laddr_s);
end
end
@ -204,6 +215,10 @@ module axi_dacfifo_dac (
(MEM_RATIO == 2) ? {axi_mem_waddr, 1'b0} :
(MEM_RATIO == 4) ? {axi_mem_waddr, 2'b0} :
{axi_mem_waddr, 3'b0};
assign axi_mem_laddr_s = (MEM_RATIO == 1) ? axi_mem_laddr :
(MEM_RATIO == 2) ? {axi_mem_laddr, 1'b0} :
(MEM_RATIO == 4) ? {axi_mem_laddr, 2'b0} :
{axi_mem_laddr, 3'b0};
// incomming data flow control
@ -268,42 +283,63 @@ module axi_dacfifo_dac (
dac_mem_waddr <= 'b0;
dac_mem_waddr_m1 <= 'b0;
dac_mem_waddr_m2 <= 'b0;
dac_mem_laddr <= 'b0;
dac_mem_laddr_m1 <= 'b0;
dac_mem_laddr_m2 <= 'b0;
dac_dlast <= 1'b0;
dac_dlast_m1 <= 1'b0;
dac_dlast_m2 <= 1'b0;
end else begin
dac_mem_waddr_m1 <= axi_mem_waddr_g;
dac_mem_waddr_m2 <= dac_mem_waddr_m1;
dac_mem_waddr <= g2b(dac_mem_waddr_m2);
dac_mem_laddr_m1 <= axi_mem_laddr_g;
dac_mem_laddr_m2 <= dac_mem_laddr_m1;
dac_mem_laddr <= g2b(dac_mem_laddr_m2);
dac_dlast_m1 <= axi_dlast;
dac_dlast_m2 <= dac_dlast_m1;
dac_dlast <= dac_dlast_m2;
end
end
assign dac_mem_addr_diff_s = {1'b1, dac_mem_waddr} - dac_mem_raddr;
assign dac_mem_raddr_diff_s = {1'b1, dac_mem_raddr_next} - dac_mem_raddr;
assign dac_mem_valid_s = (dac_mem_enable) ? dac_valid : 1'b0;
// CDC for the dma_last_addr
// CDC for the dma_last_beats
always @(posedge dac_clk) begin
if (dac_rst == 1'b1) begin
dac_last_raddr <= 32'b0;
dac_last_raddr_m <= 32'b0;
dac_last_beats <= 32'b0;
dac_last_beats_m <= 32'b0;
end else begin
dac_last_raddr_m <= dma_last_addr;
dac_last_raddr <= dac_last_raddr_m;
dac_last_beats_m <= dma_last_beats;
dac_last_beats <= dac_last_beats_m;
end
end
// If the MEM_RATIO is grater than one, it can happen that not all the DAC beats from
// an AXI beat are valid. In this case the invalid data is dropped.
// The axi_dlast indicates the last AXI beat. The valid number of DAC beats on the last AXI beat
// commes from the AXI write module. (axi_dacfifo_wr.v)
assign dac_last_axi_beats_s = ((dac_dlast_inmem == 1'b1) && (dac_mem_raddr >= dac_mem_laddr) && (dac_mem_raddr < dac_mem_laddr + MEM_RATIO)) ? 1'b1 : 1'b0;
always @(posedge dac_clk) begin
if (dac_xfer_out == 1'b0) begin
dac_mem_raddr <= 'd0;
dac_mem_raddr_next <= DAC_ARINCR;
dac_mem_raddr_g <= 'd0;
dac_mem_addr_diff <= 'd0;
dac_beat_cnt <= 'd0;
dac_dlast_inmem <= 1'b0;
end else begin
dac_mem_addr_diff <= dac_mem_addr_diff_s[DAC_ADDRESS_WIDTH-1:0];
if (dac_mem_valid_s == 1'b1) begin
dac_raddr_cnt <= (dac_raddr_cnt == dac_last_raddr) ? 32'b0 : dac_raddr_cnt + 1;
dac_mem_raddr <= (dac_raddr_cnt == dac_last_raddr) ? dac_mem_raddr_next : dac_mem_raddr + 1'b1;
if (dac_dlast == 1'b1) begin
dac_dlast_inmem <= 1'b1;
end else if (dac_mem_raddr == dac_mem_laddr + MEM_RATIO) begin
dac_dlast_inmem <= 1'b0;
end
if (dac_mem_valid_s == 1'b1) begin
dac_beat_cnt <= ((dac_beat_cnt >= MEM_RATIO-1) ||
((dac_last_beats > 1'b1) && (dac_last_axi_beats_s > 1'b0) && (dac_beat_cnt == dac_last_beats-1))) ? 0 : dac_beat_cnt + 1;
dac_mem_raddr <= ((dac_last_axi_beats_s) && (dac_beat_cnt == dac_last_beats-1)) ? (dac_mem_laddr + MEM_RATIO) : dac_mem_raddr + 1'b1;
end
dac_mem_raddr_next <= (dac_mem_raddr_diff_s[DAC_ADDRESS_WIDTH-1:0] <= 1) ? dac_mem_raddr_next + DAC_ARINCR : dac_mem_raddr_next;
dac_mem_raddr_g <= b2g(dac_mem_raddr);
end
end
@ -312,15 +348,10 @@ module axi_dacfifo_dac (
always @(posedge dac_clk) begin
if(dac_xfer_out == 1'b0) begin
dac_almost_full <= 1'b0;
dac_almost_empty <= 1'b0;
dac_mem_addr_diff <= 'b0;
dac_dunf <= 1'b0;
end else begin
if (dac_mem_addr_diff < DAC_BUF_THRESHOLD_LO) begin
dac_almost_empty <= 1'b1;
end else begin
dac_almost_empty <= 1'b0;
end
dac_mem_addr_diff <= dac_mem_addr_diff_s[DAC_ADDRESS_WIDTH-1:0];
dac_dunf <= (dac_mem_addr_diff == 1'b0) ? 1'b1 : 1'b0;
end
end

View File

@ -45,6 +45,7 @@ module axi_dacfifo_rd (
axi_xfer_req,
axi_last_raddr,
axi_last_beats,
// axi read address and read data channels
@ -78,7 +79,8 @@ module axi_dacfifo_rd (
axi_dvalid,
axi_ddata,
axi_dready);
axi_dready,
axi_dlast);
// parameters
@ -93,6 +95,7 @@ module axi_dacfifo_rd (
input axi_xfer_req;
input [31:0] axi_last_raddr;
input [ 3:0] axi_last_beats;
// axi interface
@ -127,25 +130,30 @@ module axi_dacfifo_rd (
output axi_dvalid;
output [(AXI_DATA_WIDTH-1):0] axi_ddata;
input axi_dready;
output axi_dlast;
// internal registers
reg [ 31:0] axi_rd_addr_h = 32'b0;
reg axi_rnext = 1'b0;
reg axi_ractive = 1'b0;
reg axi_arvalid = 1'b0;
reg [ 31:0] axi_araddr = 32'b0;
reg [ 31:0] axi_araddr_prev = 32'b0;
reg [(AXI_DATA_WIDTH-1):0] axi_ddata = 'b0;
reg axi_dvalid = 1'b0;
reg axi_dlast = 1'b0;
reg axi_rready = 1'b0;
reg axi_rerror = 1'b0;
reg [ 1:0] axi_xfer_req_m = 2'b0;
reg [ 4:0] axi_last_beats_cntr = 16'b0;
// internal signals
wire axi_ready_s;
wire axi_xfer_req_init;
wire axi_dvalid_s;
wire axi_dlast_s;
wire [ 4:0] axi_last_beats_s;
assign axi_ready_s = (~axi_arvalid | axi_arready) & axi_dready;
@ -170,6 +178,16 @@ module axi_dacfifo_rd (
assign axi_xfer_req_init = axi_xfer_req_m[0] & ~axi_xfer_req_m[1];
always @(posedge axi_clk) begin
if ((axi_resetn == 1'b0) || (axi_xfer_req == 1'b0)) begin
axi_last_beats_cntr <= 0;
end else begin
if ((axi_rready == 1'b1) && (axi_rvalid == 1'b1)) begin
axi_last_beats_cntr <= (axi_rlast == 1'b1) ? 0 : axi_last_beats_cntr + 1;
end
end
end
// address channel
assign axi_arid = 4'b0000;
@ -185,8 +203,8 @@ module axi_dacfifo_rd (
always @(posedge axi_clk) begin
if (axi_resetn == 1'b0) begin
axi_arvalid <= 'd0;
axi_araddr <= 'd0;
axi_rd_addr_h <= 'd0;
axi_araddr <= AXI_ADDRESS;
axi_araddr_prev <= AXI_ADDRESS;
end else begin
if (axi_arvalid == 1'b1) begin
if (axi_arready == 1'b1) begin
@ -197,20 +215,20 @@ module axi_dacfifo_rd (
axi_arvalid <= 1'b1;
end
end
if ((axi_xfer_req_init == 1'b1)) begin
axi_araddr <= AXI_ADDRESS;
axi_rd_addr_h <= axi_last_raddr;
end else if ((axi_xfer_req == 1'b1) &&
(axi_arvalid == 1'b1) &&
(axi_arready == 1'b1)) begin
axi_araddr <= (axi_araddr >= axi_rd_addr_h) ? AXI_ADDRESS : axi_araddr + AXI_AWINCR;
if ((axi_xfer_req == 1'b1) &&
(axi_arvalid == 1'b1) &&
(axi_arready == 1'b1)) begin
axi_araddr <= (axi_araddr >= axi_last_raddr) ? AXI_ADDRESS : axi_araddr + AXI_AWINCR;
axi_araddr_prev <= axi_araddr;
end
end
end
// read data channel
assign axi_dvalid_s = axi_rvalid & axi_rready;
assign axi_last_beats_s = {1'b0, axi_last_beats} - 1;
assign axi_dvalid_s = ((axi_last_beats_cntr > axi_last_beats_s) && (axi_araddr_prev == axi_last_raddr)) ? 0 : axi_rvalid & axi_rready;
assign axi_dlast_s = (axi_araddr_prev == axi_last_raddr) ? 1 : 0;
always @(posedge axi_clk) begin
if (axi_resetn == 1'b0) begin
@ -220,6 +238,7 @@ module axi_dacfifo_rd (
end else begin
axi_ddata <= axi_rdata;
axi_dvalid <= axi_dvalid_s;
axi_dlast <= axi_dlast_s;
if (axi_xfer_req == 1'b1) begin
axi_rready <= axi_rvalid;
end

View File

@ -52,11 +52,12 @@ module axi_dacfifo_wr (
dma_xfer_req,
dma_xfer_last,
dma_last_beats,
// syncronization for the read side
axi_last_addr,
dma_last_addr,
axi_last_beats,
axi_xfer_out,
// axi write address, write data and write response channels
@ -124,9 +125,10 @@ module axi_dacfifo_wr (
input dma_xfer_req;
input dma_xfer_last;
output [ 3:0] dma_last_beats;
output [31:0] axi_last_addr;
output [31:0] dma_last_addr;
output [ 3:0] axi_last_beats;
output axi_xfer_out;
// axi interface
@ -171,8 +173,8 @@ module axi_dacfifo_wr (
reg dma_rst_m1 = 1'b0;
reg dma_rst_m2 = 1'b0;
reg [ 2:0] dma_mem_last_read_toggle_m = 3'b0;
reg [31:0] dma_addr_cnt = 32'b0;
reg [31:0] dma_last_addr = 32'b0;
reg dma_xfer_req_d = 1'b0;
reg [ 3:0] dma_last_beats = 4'b0;
reg [ 4:0] axi_xfer_req_m = 3'b0;
reg [ 4:0] axi_xfer_last_m = 3'b0;
@ -196,6 +198,7 @@ module axi_dacfifo_wr (
reg axi_reset = 1'b0;
reg axi_xfer_out = 1'b0;
reg [31:0] axi_last_addr = 32'b0;
reg [ 3:0] axi_last_beats = 15'b0;
reg axi_awvalid = 1'b0;
reg [31:0] axi_awaddr = 32'b0;
reg axi_xfer_init = 1'b0;
@ -210,6 +213,7 @@ module axi_dacfifo_wr (
wire [(DMA_MEM_ADDRESS_WIDTH):0] dma_mem_addr_diff_s;
wire [(DMA_MEM_ADDRESS_WIDTH-1):0] dma_mem_raddr_s;
wire dma_mem_last_read_s;
wire dma_xfer_init;
wire dma_mem_wea_s;
wire dma_rst_s;
@ -304,10 +308,21 @@ module axi_dacfifo_wr (
end
assign dma_rst_s = dma_rst_m2;
// Write address generation for the asymmetric memory
// DMA beat counter
// There is no underflow or overflow. All the data movements are controlled by
// this module.
assign dma_xfer_init = dma_xfer_req & ~dma_xfer_req_d;
always @(posedge dma_clk) begin
dma_xfer_req_d <= dma_xfer_req;
if ((dma_rst_s == 1'b1) || (dma_xfer_init == 1'b1)) begin
dma_last_beats <= 4'b0;
end else begin
if ((dma_ready == 1'b1) && (dma_valid == 1'b1)) begin
dma_last_beats <= (dma_last_beats < MEM_RATIO-1) ? dma_last_beats + 1 : 0;
end
end
end
// Write address generation for the asymmetric memory
assign dma_mem_addr_diff_s = {1'b1, dma_mem_waddr} - dma_mem_raddr_s;
assign dma_mem_raddr_s = (MEM_RATIO == 1) ? dma_mem_raddr :
@ -327,6 +342,11 @@ module axi_dacfifo_wr (
dma_mem_last_read_toggle_m = {dma_mem_last_read_toggle_m[1:0], axi_mem_last_read_toggle};
if (dma_mem_wea_s == 1'b1) begin
dma_mem_waddr <= dma_mem_waddr + 8'b1;
if (dma_xfer_last == 1'b1) begin
if (dma_last_beats != (MEM_RATIO - 1)) begin
dma_mem_waddr <= dma_mem_waddr + (MEM_RATIO - dma_last_beats);
end
end
end
if (dma_mem_last_read_s == 1'b1) begin
dma_mem_waddr <= 'h0;
@ -357,21 +377,6 @@ module axi_dacfifo_wr (
end
end
// An absolute address counter with DMA's granularity, this address will be
// used on read back
always @(posedge dma_clk) begin
if (dma_rst_s == 1'b1) begin
dma_addr_cnt <= 32'b0;
dma_last_addr <= 32'b0;
end else begin
if((dma_valid == 1'b1) && (dma_xfer_req == 1'b1)) begin
dma_addr_cnt <= (dma_xfer_last == 1'b1) ? 32'b0 : dma_addr_cnt + 1;
dma_last_addr <= (dma_xfer_last == 1'b1) ? dma_addr_cnt : dma_last_addr;
end
end
end
// Read address generation for the asymmetric memory
// CDC for the memory write address, xfer_req and xfer_last
@ -546,4 +551,18 @@ module axi_dacfifo_wr (
end
end
// AXI beat counter
always @(posedge axi_clk) begin
if(axi_resetn == 1'b0) begin
axi_last_beats <= 4'b0;
end else begin
if ((axi_endof_transaction == 1'b1) && (axi_awready == 1'b1) && (axi_awvalid == 1'b1)) begin
axi_last_beats <= axi_mem_addr_diff;
end else begin
axi_last_beats <= axi_last_beats;
end
end
end
endmodule