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 [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),

View File

@ -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

View File

@ -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

View File

@ -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