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.
main
Istvan Csomortani 2016-05-17 18:43:59 +03:00
parent 88e0cfec42
commit c8d4f956e7
4 changed files with 170 additions and 89 deletions

View File

@ -196,6 +196,7 @@ module axi_dacfifo (
wire axi_rd_valid_s; wire axi_rd_valid_s;
wire [31:0] axi_rd_lastaddr_s; wire [31:0] axi_rd_lastaddr_s;
wire axi_xfer_req_s; wire axi_xfer_req_s;
wire [31:0] dma_last_addr_s;
wire [(DAC_DATA_WIDTH-1):0] dac_data_s; wire [(DAC_DATA_WIDTH-1):0] dac_data_s;
wire dma_ready_s; wire dma_ready_s;
@ -217,6 +218,7 @@ module axi_dacfifo (
.dma_xfer_req (dma_xfer_req), .dma_xfer_req (dma_xfer_req),
.dma_xfer_last (dma_xfer_last), .dma_xfer_last (dma_xfer_last),
.axi_last_raddr (axi_rd_lastaddr_s), .axi_last_raddr (axi_rd_lastaddr_s),
.dma_last_addr (dma_last_addr_s),
.axi_xfer_out (axi_xfer_req_s), .axi_xfer_out (axi_xfer_req_s),
.axi_clk (axi_clk), .axi_clk (axi_clk),
.axi_resetn (axi_resetn), .axi_resetn (axi_resetn),
@ -289,6 +291,7 @@ module axi_dacfifo (
.axi_ddata (axi_rd_data_s), .axi_ddata (axi_rd_data_s),
.axi_dready (axi_rd_ready_s), .axi_dready (axi_rd_ready_s),
.axi_xfer_req (axi_xfer_req_s), .axi_xfer_req (axi_xfer_req_s),
.dma_last_addr (dma_last_addr_s),
.dac_clk (dac_clk), .dac_clk (dac_clk),
.dac_rst (dac_rst), .dac_rst (dac_rst),
.dac_valid (dac_valid), .dac_valid (dac_valid),

View File

@ -47,6 +47,8 @@ module axi_dacfifo_dac (
axi_dready, axi_dready,
axi_xfer_req, axi_xfer_req,
dma_last_addr,
dac_clk, dac_clk,
dac_rst, dac_rst,
dac_valid, dac_valid,
@ -67,8 +69,13 @@ module axi_dacfifo_dac (
(MEM_RATIO == 2) ? (DAC_ADDRESS_WIDTH - 1) : (MEM_RATIO == 2) ? (DAC_ADDRESS_WIDTH - 1) :
(MEM_RATIO == 4) ? (DAC_ADDRESS_WIDTH - 2) : (MEM_RATIO == 4) ? (DAC_ADDRESS_WIDTH - 2) :
(DAC_ADDRESS_WIDTH - 3); (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 // dma write
@ -78,6 +85,8 @@ module axi_dacfifo_dac (
output axi_dready; output axi_dready;
input axi_xfer_req; input axi_xfer_req;
input [32:0] dma_last_addr;
// dac read // dac read
input dac_clk; input dac_clk;
@ -89,34 +98,44 @@ module axi_dacfifo_dac (
// internal registers // internal registers
reg [(AXI_ADDRESS_WIDTH-1):0] axi_waddr = 'd0; reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_waddr_g = 'd0; reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_waddr_g = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_raddr = 'd0; reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_raddr_m = 'd0; reg [(DAC_ADDRESS_WIDTH-1):0] axi_mem_raddr_m = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] axi_addr_diff = 'd0; reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_addr_diff = 'd0;
reg axi_dready = '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_ADDRESS_WIDTH-1):0] dac_mem_raddr = 'd0;
reg dac_rd_d = 'd0; reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_raddr_next = 'd0;
reg [(DAC_DATA_WIDTH-1):0] dac_rdata_d = 'd0; reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_raddr_g = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_raddr = 'd0; reg [(DAC_ADDRESS_WIDTH-1):0] dac_mem_waddr = 'd0;
reg [(DAC_ADDRESS_WIDTH-1):0] dac_raddr_g = '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 [ 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 // internal signals
wire [DAC_ADDRESS_WIDTH:0] axi_addr_diff_s; wire [AXI_ADDRESS_WIDTH:0] axi_mem_addr_diff_s;
wire [(DAC_ADDRESS_WIDTH-1):0] axi_waddr_s; wire [(AXI_ADDRESS_WIDTH-1):0] axi_mem_raddr_s;
wire dac_wready_s; wire [(DAC_ADDRESS_WIDTH-1):0] axi_mem_waddr_s;
wire dac_rd_s;
wire [(DAC_DATA_WIDTH-1):0] dac_rdata_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 // binary to grey conversion
@ -158,83 +177,136 @@ module axi_dacfifo_dac (
always @(posedge axi_clk) begin always @(posedge axi_clk) begin
if (axi_xfer_req == 1'b0) begin if (axi_xfer_req == 1'b0) begin
axi_waddr <= 'd0; axi_mem_waddr <= 'd0;
axi_waddr_g <= 'd0; axi_mem_waddr_g <= 'd0;
end else begin end else begin
if (axi_dvalid == 1'b1) begin if (axi_dvalid == 1'b1) begin
axi_waddr <= axi_waddr + 1'b1; axi_mem_waddr <= axi_mem_waddr + 1'b1;
end end
axi_waddr_g <= b2g(axi_waddr_s); axi_mem_waddr_g <= b2g(axi_mem_waddr_s);
end end
end end
// underflow / overflow // scale the axi_mem_* addresses
assign axi_addr_diff_s = {1'b1, axi_waddr_s} - axi_raddr; assign axi_mem_raddr_s = (MEM_RATIO == 1) ? axi_mem_raddr :
assign axi_waddr_s = (MEM_RATIO == 1) ? axi_waddr : (MEM_RATIO == 2) ? axi_mem_raddr[(DAC_ADDRESS_WIDTH-1):1] :
(MEM_RATIO == 2) ? {axi_waddr, 1'd0} : (MEM_RATIO == 4) ? axi_mem_raddr[(DAC_ADDRESS_WIDTH-1):2] :
(MEM_RATIO == 4) ? {axi_waddr, 2'd0} : axi_mem_raddr[(DAC_ADDRESS_WIDTH-1):3];
{axi_waddr, 3'd0}; 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 always @(posedge axi_clk) begin
if (axi_xfer_req == 1'b0) begin if (axi_xfer_req == 1'b0) begin
axi_addr_diff <= 'd0; axi_mem_addr_diff <= 'd0;
axi_raddr <= 'd0; axi_mem_raddr <= 'd0;
axi_raddr_m <= 'd0; axi_mem_raddr_m <= 'd0;
axi_dready <= 'd0; axi_dready <= 'd0;
axi_almost_full <= 1'b0;
axi_dwunf <= 1'b0;
axi_almost_empty <= 1'b0;
end else begin end else begin
axi_raddr_m <= g2b(dac_raddr_g); axi_mem_raddr_m <= g2b(dac_mem_raddr_g);
axi_raddr <= axi_raddr_m; axi_mem_raddr <= axi_mem_raddr_m;
axi_addr_diff <= axi_addr_diff_s[DAC_ADDRESS_WIDTH-1:0]; axi_mem_addr_diff <= axi_mem_addr_diff_s[AXI_ADDRESS_WIDTH-1:0];
if (axi_addr_diff >= BUF_THRESHOLD_HI) begin if (axi_mem_addr_diff >= AXI_BUF_THRESHOLD_HI) begin
axi_dready <= 1'b0; 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; axi_dready <= 1'b1;
end end
if (axi_addr_diff > BUF_THRESHOLD_HI) begin end
axi_almost_full <= 1'b1; end
end else begin
axi_almost_full <= 1'b0; // 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 end
if (axi_addr_diff < BUF_THRESHOLD_LO) begin if ((dac_mem_init == 1'b1) && (dac_mem_addr_diff > DAC_BUF_THRESHOLD_LO)) begin
axi_almost_empty <= 1'b1; dac_mem_init <= 1'b0;
end else begin
axi_almost_empty <= 1'b0;
end 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
end end
always @(posedge dac_clk) begin always @(posedge dac_clk) begin
dac_dunf_m <= {dac_dunf_m[1:0], axi_dwunf}; if (dac_xfer_out == 1'b0) begin
dac_xfer_req_m <= {dac_xfer_req_m[1:0], axi_xfer_req}; 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 end
assign dac_dunf = dac_dunf_m[2]; // underflow generation, there is no overflow
assign dac_xfer_out = dac_xfer_req_m[2];
// read interface
assign dac_rd_s = dac_xfer_out & dac_valid;
always @(posedge dac_clk) begin always @(posedge dac_clk) begin
if (dac_xfer_out == 1'b0) begin if(dac_xfer_out == 1'b0) begin
dac_rd <= 'd0; dac_almost_full <= 1'b0;
dac_rd_d <= 'd0; dac_almost_empty <= 1'b0;
dac_rdata_d <= 'd0; dac_dunf <= 1'b0;
dac_raddr <= 'd0;
dac_raddr_g <= 'd0;
end else begin end else begin
dac_rd <= dac_rd_s; if (dac_mem_addr_diff < DAC_BUF_THRESHOLD_LO) begin
dac_rd_d <= dac_rd; dac_almost_empty <= 1'b1;
dac_rdata_d <= dac_rdata_s; end else begin
if (dac_rd_s == 1'b1) begin dac_almost_empty <= 1'b0;
dac_raddr <= dac_raddr + 1'b1;
end end
dac_raddr_g <= b2g(dac_raddr); dac_dunf <= (dac_mem_addr_diff == 0) ? 1'b1 : 1'b0;
end end
end end
@ -248,22 +320,11 @@ module axi_dacfifo_dac (
i_mem_asym ( i_mem_asym (
.clka (axi_clk), .clka (axi_clk),
.wea (axi_dvalid), .wea (axi_dvalid),
.addra (axi_waddr), .addra (axi_mem_waddr),
.dina (axi_ddata), .dina (axi_ddata),
.clkb (dac_clk), .clkb (dac_clk),
.addrb (dac_raddr), .addrb (dac_mem_raddr),
.doutb (dac_rdata_s)); .doutb (dac_data));
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));
endmodule endmodule

View File

@ -186,6 +186,7 @@ module axi_dacfifo_rd (
if (axi_resetn == 1'b0) begin if (axi_resetn == 1'b0) begin
axi_arvalid <= 'd0; axi_arvalid <= 'd0;
axi_araddr <= 'd0; axi_araddr <= 'd0;
axi_rd_addr_h <= 'd0;
end else begin end else begin
if (axi_arvalid == 1'b1) begin if (axi_arvalid == 1'b1) begin
if (axi_arready == 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) && end else if ((axi_xfer_req == 1'b1) &&
(axi_arvalid == 1'b1) && (axi_arvalid == 1'b1) &&
(axi_arready == 1'b1)) begin (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 end
end end

View File

@ -56,6 +56,7 @@ module axi_dacfifo_wr (
// syncronization for the read side // syncronization for the read side
axi_last_raddr, axi_last_raddr,
dma_last_addr,
axi_xfer_out, axi_xfer_out,
// axi write address, write data and write response channels // axi write address, write data and write response channels
@ -122,6 +123,7 @@ module axi_dacfifo_wr (
input dma_xfer_last; input dma_xfer_last;
output [31:0] axi_last_raddr; output [31:0] axi_last_raddr;
output [31:0] dma_last_addr;
output axi_xfer_out; output axi_xfer_out;
// axi interface // axi interface
@ -165,6 +167,8 @@ module axi_dacfifo_wr (
reg dma_ready = 'd0; reg dma_ready = 'd0;
reg dma_rst_m1 = 1'b0; reg dma_rst_m1 = 1'b0;
reg dma_rst_m2 = 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_req_m = 3'b0;
reg [ 2:0] axi_xfer_last_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 // 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 always @(posedge dma_clk) begin
if (dma_rst_s == 1'b1) begin if (dma_rst_s == 1'b1) begin
dma_mem_waddr <= 8'h0; 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 end else if ((axi_awvalid == 1'b1) && (axi_awready == 1'b1)) begin
axi_awaddr <= axi_awaddr + AXI_AWINCR; axi_awaddr <= axi_awaddr + AXI_AWINCR;
end end
if(axi_xfer_last_m[2] == 1) begin if ((axi_xfer_req_m[2] == 1) && (axi_xfer_last_m[2] == 1)) begin
axi_last_raddr <= axi_awaddr; axi_last_raddr <= axi_awaddr - AXI_AWINCR;
axi_xfer_out <= 1'b1; axi_xfer_out <= 1'b1;
end end
end end