From c8d4f956e7956c1af8e7924da4801110329c3452 Mon Sep 17 00:00:00 2001 From: Istvan Csomortani Date: Tue, 17 May 2016 18:43:59 +0300 Subject: [PATCH] axi_dacfifo: Update the read back logic Update the readback logic of the FIFO. The controller uses a relative address counter, which counts the DMA beats. The readback logic uses the last value of that counter to define the wrapping address. The aditional data from the last AXI burst, if there is any, will be dropped. --- library/axi_dacfifo/axi_dacfifo.v | 3 + library/axi_dacfifo/axi_dacfifo_dac.v | 233 ++++++++++++++++---------- library/axi_dacfifo/axi_dacfifo_rd.v | 3 +- library/axi_dacfifo/axi_dacfifo_wr.v | 20 ++- 4 files changed, 170 insertions(+), 89 deletions(-) diff --git a/library/axi_dacfifo/axi_dacfifo.v b/library/axi_dacfifo/axi_dacfifo.v index 01f140e0a..f6b3ccc96 100644 --- a/library/axi_dacfifo/axi_dacfifo.v +++ b/library/axi_dacfifo/axi_dacfifo.v @@ -196,6 +196,7 @@ module axi_dacfifo ( wire axi_rd_valid_s; wire [31:0] axi_rd_lastaddr_s; wire axi_xfer_req_s; + wire [31:0] dma_last_addr_s; wire [(DAC_DATA_WIDTH-1):0] dac_data_s; wire dma_ready_s; @@ -217,6 +218,7 @@ module axi_dacfifo ( .dma_xfer_req (dma_xfer_req), .dma_xfer_last (dma_xfer_last), .axi_last_raddr (axi_rd_lastaddr_s), + .dma_last_addr (dma_last_addr_s), .axi_xfer_out (axi_xfer_req_s), .axi_clk (axi_clk), .axi_resetn (axi_resetn), @@ -289,6 +291,7 @@ module axi_dacfifo ( .axi_ddata (axi_rd_data_s), .axi_dready (axi_rd_ready_s), .axi_xfer_req (axi_xfer_req_s), + .dma_last_addr (dma_last_addr_s), .dac_clk (dac_clk), .dac_rst (dac_rst), .dac_valid (dac_valid), diff --git a/library/axi_dacfifo/axi_dacfifo_dac.v b/library/axi_dacfifo/axi_dacfifo_dac.v index 44a47ea1f..3aeeb3d94 100644 --- a/library/axi_dacfifo/axi_dacfifo_dac.v +++ b/library/axi_dacfifo/axi_dacfifo_dac.v @@ -47,6 +47,8 @@ module axi_dacfifo_dac ( axi_dready, axi_xfer_req, + dma_last_addr, + dac_clk, dac_rst, dac_valid, @@ -67,8 +69,13 @@ module axi_dacfifo_dac ( (MEM_RATIO == 2) ? (DAC_ADDRESS_WIDTH - 1) : (MEM_RATIO == 4) ? (DAC_ADDRESS_WIDTH - 2) : (DAC_ADDRESS_WIDTH - 3); - localparam BUF_THRESHOLD_LO = 8'd32; - localparam BUF_THRESHOLD_HI = 8'd240; + + // BUF_THRESHOLD_LO will make sure that there are always at least two burst in the memmory + localparam AXI_BUF_THRESHOLD_LO = 3 * (AXI_LENGTH+1); + localparam AXI_BUF_THRESHOLD_HI = {(AXI_ADDRESS_WIDTH){1'b1}} - (AXI_LENGTH+1); + localparam DAC_BUF_THRESHOLD_LO = 3 * (AXI_LENGTH+1) * MEM_RATIO; + localparam DAC_BUF_THRESHOLD_HI = {(DAC_ADDRESS_WIDTH){1'b1}} - (AXI_LENGTH+1) * MEM_RATIO; + localparam DAC_ARINCR = (AXI_LENGTH+1) * MEM_RATIO; // dma write @@ -78,6 +85,8 @@ module axi_dacfifo_dac ( output axi_dready; input axi_xfer_req; + input [32:0] dma_last_addr; + // dac read input dac_clk; @@ -89,34 +98,44 @@ module axi_dacfifo_dac ( // internal registers - reg [(AXI_ADDRESS_WIDTH-1):0] axi_waddr = 'd0; - reg [(DAC_ADDRESS_WIDTH-1):0] axi_waddr_g = 'd0; - reg [(DAC_ADDRESS_WIDTH-1):0] axi_raddr = 'd0; - reg [(DAC_ADDRESS_WIDTH-1):0] axi_raddr_m = 'd0; - reg [(DAC_ADDRESS_WIDTH-1):0] axi_addr_diff = 'd0; + reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'd0; + reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_waddr_g = 'd0; + reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr = 'd0; + reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr_m = 'd0; + reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_addr_diff = 'd0; reg axi_dready = 'd0; - reg axi_almost_full = 1'b0; - reg axi_dwunf = 1'b0; - reg axi_almost_empty = 1'b0; - reg dac_rd = 'd0; - reg dac_rd_d = 'd0; - reg [(DAC_DATA_WIDTH-1):0] dac_rdata_d = 'd0; - reg [(DAC_ADDRESS_WIDTH-1):0] dac_raddr = 'd0; - reg [(DAC_ADDRESS_WIDTH-1):0] dac_raddr_g = '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_m = '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; + reg dac_mem_enable = 1'b0; - reg [ 2:0] dac_dunf_m = 3'b0; 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 dac_dunf = 1'b0; // internal signals - wire [DAC_ADDRESS_WIDTH:0] axi_addr_diff_s; - wire [(DAC_ADDRESS_WIDTH-1):0] axi_waddr_s; - wire dac_wready_s; - wire dac_rd_s; - wire [(DAC_DATA_WIDTH-1):0] dac_rdata_s; + 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_valid_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; // binary to grey conversion @@ -158,83 +177,136 @@ module axi_dacfifo_dac ( always @(posedge axi_clk) begin if (axi_xfer_req == 1'b0) begin - axi_waddr <= 'd0; - axi_waddr_g <= 'd0; + axi_mem_waddr <= 'd0; + axi_mem_waddr_g <= 'd0; end else begin if (axi_dvalid == 1'b1) begin - axi_waddr <= axi_waddr + 1'b1; + axi_mem_waddr <= axi_mem_waddr + 1'b1; end - axi_waddr_g <= b2g(axi_waddr_s); + axi_mem_waddr_g <= b2g(axi_mem_waddr_s); end end - // underflow / overflow + // scale the axi_mem_* addresses - assign axi_addr_diff_s = {1'b1, axi_waddr_s} - axi_raddr; - assign axi_waddr_s = (MEM_RATIO == 1) ? axi_waddr : - (MEM_RATIO == 2) ? {axi_waddr, 1'd0} : - (MEM_RATIO == 4) ? {axi_waddr, 2'd0} : - {axi_waddr, 3'd0}; + assign axi_mem_raddr_s = (MEM_RATIO == 1) ? axi_mem_raddr : + (MEM_RATIO == 2) ? axi_mem_raddr[(DAC_ADDRESS_WIDTH-1):1] : + (MEM_RATIO == 4) ? axi_mem_raddr[(DAC_ADDRESS_WIDTH-1):2] : + axi_mem_raddr[(DAC_ADDRESS_WIDTH-1):3]; + assign axi_mem_waddr_s = (MEM_RATIO == 1) ? axi_mem_waddr : + (MEM_RATIO == 2) ? {axi_mem_waddr, 1'b0} : + (MEM_RATIO == 4) ? {axi_mem_waddr, 2'b0} : + {axi_mem_waddr, 3'b0}; + + // incomming data flow control + + assign axi_mem_addr_diff_s = {1'b1, axi_mem_waddr} - axi_mem_raddr_s; always @(posedge axi_clk) begin if (axi_xfer_req == 1'b0) begin - axi_addr_diff <= 'd0; - axi_raddr <= 'd0; - axi_raddr_m <= 'd0; + axi_mem_addr_diff <= 'd0; + axi_mem_raddr <= 'd0; + axi_mem_raddr_m <= 'd0; axi_dready <= 'd0; - axi_almost_full <= 1'b0; - axi_dwunf <= 1'b0; - axi_almost_empty <= 1'b0; end else begin - axi_raddr_m <= g2b(dac_raddr_g); - axi_raddr <= axi_raddr_m; - axi_addr_diff <= axi_addr_diff_s[DAC_ADDRESS_WIDTH-1:0]; - if (axi_addr_diff >= BUF_THRESHOLD_HI) begin + axi_mem_raddr_m <= g2b(dac_mem_raddr_g); + axi_mem_raddr <= axi_mem_raddr_m; + axi_mem_addr_diff <= axi_mem_addr_diff_s[AXI_ADDRESS_WIDTH-1:0]; + if (axi_mem_addr_diff >= AXI_BUF_THRESHOLD_HI) begin axi_dready <= 1'b0; - end else if (axi_addr_diff <= BUF_THRESHOLD_LO) begin + end else if (axi_mem_addr_diff <= AXI_BUF_THRESHOLD_LO) begin axi_dready <= 1'b1; end - if (axi_addr_diff > BUF_THRESHOLD_HI) begin - axi_almost_full <= 1'b1; - end else begin - axi_almost_full <= 1'b0; + end + end + + // CDC for xfer_req signal + + always @(posedge dac_clk) begin + dac_xfer_req_m <= {dac_xfer_req_m[1:0], axi_xfer_req}; + end + + assign dac_xfer_out = dac_xfer_req_m[2]; + assign dac_xfer_init_s = ~dac_xfer_req_m[2] & dac_xfer_req_m[1]; + + // read interface + + always @(posedge dac_clk) begin + if (dac_xfer_out == 1'b0) begin + dac_mem_init <= 1'b0; + dac_mem_init_d <= 1'b0; + dac_mem_enable <= 1'b0; + end else begin + if (dac_xfer_init == 1'b1) begin + dac_mem_init <= 1'b1; end - if (axi_addr_diff < BUF_THRESHOLD_LO) begin - axi_almost_empty <= 1'b1; - end else begin - axi_almost_empty <= 1'b0; + if ((dac_mem_init == 1'b1) && (dac_mem_addr_diff > DAC_BUF_THRESHOLD_LO)) begin + dac_mem_init <= 1'b0; end - axi_dwunf <= (axi_addr_diff == 0) ? 1'b1 : 1'b0; + dac_mem_init_d <= dac_mem_init; + // memory is ready when the initial fill up is done + dac_mem_enable <= (dac_mem_init_d & ~dac_mem_init) ? 1'b1 : dac_mem_enable; + end + dac_xfer_init <= dac_xfer_init_s; + end + + always @(posedge dac_clk) begin + if (dac_xfer_out == 1'b0) begin + dac_mem_waddr <= 'b0; + dac_mem_waddr_m <= 'b0; + end else begin + dac_mem_waddr_m <= g2b(axi_mem_waddr_g); + dac_mem_waddr <= dac_mem_waddr_m; + 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 + + always @(posedge dac_clk) begin + if (dac_rst == 1'b1) begin + dac_last_raddr <= 32'b0; + dac_last_raddr_m <= 32'b0; + end else begin + dac_last_raddr_m <= dma_last_addr; + dac_last_raddr <= dac_last_raddr_m; end end always @(posedge dac_clk) begin - dac_dunf_m <= {dac_dunf_m[1:0], axi_dwunf}; - dac_xfer_req_m <= {dac_xfer_req_m[1:0], axi_xfer_req}; + 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; + 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; + 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 - assign dac_dunf = dac_dunf_m[2]; - assign dac_xfer_out = dac_xfer_req_m[2]; - - // read interface - - assign dac_rd_s = dac_xfer_out & dac_valid; + // underflow generation, there is no overflow always @(posedge dac_clk) begin - if (dac_xfer_out == 1'b0) begin - dac_rd <= 'd0; - dac_rd_d <= 'd0; - dac_rdata_d <= 'd0; - dac_raddr <= 'd0; - dac_raddr_g <= 'd0; + if(dac_xfer_out == 1'b0) begin + dac_almost_full <= 1'b0; + dac_almost_empty <= 1'b0; + dac_dunf <= 1'b0; end else begin - dac_rd <= dac_rd_s; - dac_rd_d <= dac_rd; - dac_rdata_d <= dac_rdata_s; - if (dac_rd_s == 1'b1) begin - dac_raddr <= dac_raddr + 1'b1; + 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_raddr_g <= b2g(dac_raddr); + dac_dunf <= (dac_mem_addr_diff == 0) ? 1'b1 : 1'b0; end end @@ -248,22 +320,11 @@ module axi_dacfifo_dac ( i_mem_asym ( .clka (axi_clk), .wea (axi_dvalid), - .addra (axi_waddr), + .addra (axi_mem_waddr), .dina (axi_ddata), .clkb (dac_clk), - .addrb (dac_raddr), - .doutb (dac_rdata_s)); - - ad_axis_inf_rx #(.DATA_WIDTH(DAC_DATA_WIDTH)) i_axis_inf ( - .clk (dac_clk), - .rst (dac_rst), - .valid (dac_rd_d), - .last (1'd0), - .data (dac_rdata_d), - .inf_valid (dac_valid_s), - .inf_last (), - .inf_data (dac_data), - .inf_ready (dac_valid)); + .addrb (dac_mem_raddr), + .doutb (dac_data)); endmodule diff --git a/library/axi_dacfifo/axi_dacfifo_rd.v b/library/axi_dacfifo/axi_dacfifo_rd.v index b3ec1388f..f4f309fc7 100644 --- a/library/axi_dacfifo/axi_dacfifo_rd.v +++ b/library/axi_dacfifo/axi_dacfifo_rd.v @@ -186,6 +186,7 @@ module axi_dacfifo_rd ( if (axi_resetn == 1'b0) begin axi_arvalid <= 'd0; axi_araddr <= 'd0; + axi_rd_addr_h <= 'd0; end else begin if (axi_arvalid == 1'b1) begin if (axi_arready == 1'b1) begin @@ -202,7 +203,7 @@ module axi_dacfifo_rd ( end else if ((axi_xfer_req == 1'b1) && (axi_arvalid == 1'b1) && (axi_arready == 1'b1)) begin - axi_araddr <= ((axi_araddr + AXI_AWINCR) >= axi_rd_addr_h) ? AXI_ADDRESS : axi_araddr + AXI_AWINCR; + axi_araddr <= (axi_araddr >= axi_rd_addr_h) ? AXI_ADDRESS : axi_araddr + AXI_AWINCR; end end end diff --git a/library/axi_dacfifo/axi_dacfifo_wr.v b/library/axi_dacfifo/axi_dacfifo_wr.v index 073e56d1d..71c4ccd95 100644 --- a/library/axi_dacfifo/axi_dacfifo_wr.v +++ b/library/axi_dacfifo/axi_dacfifo_wr.v @@ -56,6 +56,7 @@ module axi_dacfifo_wr ( // syncronization for the read side axi_last_raddr, + dma_last_addr, axi_xfer_out, // axi write address, write data and write response channels @@ -122,6 +123,7 @@ module axi_dacfifo_wr ( input dma_xfer_last; output [31:0] axi_last_raddr; + output [31:0] dma_last_addr; output axi_xfer_out; // axi interface @@ -165,6 +167,8 @@ module axi_dacfifo_wr ( reg dma_ready = 'd0; reg dma_rst_m1 = 1'b0; reg dma_rst_m2 = 1'b0; + reg [31:0] dma_last_addr = 32'b0; + reg [31:0] dma_addr_cnt = 32'b0; reg [ 2:0] axi_xfer_req_m = 3'b0; reg [ 2:0] axi_xfer_last_m = 3'b0; @@ -248,6 +252,18 @@ module axi_dacfifo_wr ( // write address generation for the asymetric memory + 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 + always @(posedge dma_clk) begin if (dma_rst_s == 1'b1) begin dma_mem_waddr <= 8'h0; @@ -371,8 +387,8 @@ module axi_dacfifo_wr ( end else if ((axi_awvalid == 1'b1) && (axi_awready == 1'b1)) begin axi_awaddr <= axi_awaddr + AXI_AWINCR; end - if(axi_xfer_last_m[2] == 1) begin - axi_last_raddr <= axi_awaddr; + if ((axi_xfer_req_m[2] == 1) && (axi_xfer_last_m[2] == 1)) begin + axi_last_raddr <= axi_awaddr - AXI_AWINCR; axi_xfer_out <= 1'b1; end end