axi_dmac: Add limited TLAST support for streaming AXI source interface

Add some limit TLAST support for the streaming AXI source interface. An
asserted TLAST signal marks the end of a packet and the following data beat
is the first beat for the next packet.

Currently the DMAC does not support for completing a transfer before all
requested bytes have been transferred. So the way this limited TLAST
support is implemented is by filling the remainder of the buffer with 0x00.

While the DMAC is busy filling the buffer with zeros back-pressure is
asserted on the external streaming AXI interface by keeping TREADY
de-asserted.

The end of a buffer is marked by a transfer that has the last bit set in
the FLAGS control register.

In the future we might add support for transfer completion before all
requested bytes have been transferred.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
main
Lars-Peter Clausen 2017-12-07 18:31:10 +01:00
parent da28ee3cce
commit c6073954d9
4 changed files with 60 additions and 13 deletions

View File

@ -167,6 +167,7 @@ module axi_dmac #(
input s_axis_valid, input s_axis_valid,
input [DMA_DATA_WIDTH_SRC-1:0] s_axis_data, input [DMA_DATA_WIDTH_SRC-1:0] s_axis_data,
input [0:0] s_axis_user, input [0:0] s_axis_user,
input s_axis_last,
output s_axis_xfer_req, output s_axis_xfer_req,
// Master streaming AXI interface // Master streaming AXI interface
@ -377,7 +378,7 @@ begin
up_dma_req_valid <= 1'b0; up_dma_req_valid <= 1'b0;
up_scratch <= 'h00; up_scratch <= 'h00;
up_dma_cyclic <= 1'b0; up_dma_cyclic <= 1'b0;
up_axis_xlast <= 1'b0; up_axis_xlast <= 1'b1;
up_wack <= 1'b0; up_wack <= 1'b0;
end else begin end else begin
up_wack <= up_wreq; up_wack <= up_wreq;
@ -628,6 +629,7 @@ dmac_request_arb #(
.s_axis_valid(s_axis_valid), .s_axis_valid(s_axis_valid),
.s_axis_data(s_axis_data), .s_axis_data(s_axis_data),
.s_axis_user(s_axis_user), .s_axis_user(s_axis_user),
.s_axis_last(s_axis_last),
.s_axis_xfer_req(s_axis_xfer_req), .s_axis_xfer_req(s_axis_xfer_req),

View File

@ -45,6 +45,7 @@ adi_add_bus "s_axis" "slave" \
[list {"s_axis_ready" "TREADY"} \ [list {"s_axis_ready" "TREADY"} \
{"s_axis_valid" "TVALID"} \ {"s_axis_valid" "TVALID"} \
{"s_axis_data" "TDATA"} \ {"s_axis_data" "TDATA"} \
{"s_axis_last" "TLAST"} \
{"s_axis_user" "TUSER"} ] {"s_axis_user" "TUSER"} ]
adi_add_bus_clock "s_axis_aclk" "s_axis" adi_add_bus_clock "s_axis_aclk" "s_axis"
@ -145,8 +146,9 @@ adi_add_bus_clock "fifo_rd_clk" "fifo_rd"
adi_set_bus_dependency "fifo_rd" "fifo_rd" \ adi_set_bus_dependency "fifo_rd" "fifo_rd" \
"(spirit:decode(id('MODELPARAM_VALUE.DMA_TYPE_DEST')) = 2)" "(spirit:decode(id('MODELPARAM_VALUE.DMA_TYPE_DEST')) = 2)"
foreach port {"m_dest_axi_aresetn" "m_src_axi_aresetn" "s_axis_valid" \ foreach port {"m_dest_axi_aresetn" "m_src_axi_aresetn" \
"s_axis_data" "m_axis_ready" "fifo_wr_en" "fifo_wr_din" "fifo_rd_en"} { "s_axis_valid" "s_axis_data" "s_axis_last" "m_axis_ready" \
"fifo_wr_en" "fifo_wr_din" "fifo_rd_en"} {
set_property DRIVER_VALUE "0" [ipx::get_ports $port] set_property DRIVER_VALUE "0" [ipx::get_ports $port]
} }

View File

@ -118,6 +118,7 @@ module dmac_request_arb #(
output s_axis_ready, output s_axis_ready,
input s_axis_valid, input s_axis_valid,
input [DMA_DATA_WIDTH_SRC-1:0] s_axis_data, input [DMA_DATA_WIDTH_SRC-1:0] s_axis_data,
input s_axis_last,
input [0:0] s_axis_user, input [0:0] s_axis_user,
output s_axis_xfer_req, output s_axis_xfer_req,
@ -243,6 +244,7 @@ wire src_req_ready;
wire [DMA_ADDRESS_WIDTH_SRC-1:0] src_req_address; wire [DMA_ADDRESS_WIDTH_SRC-1:0] src_req_address;
wire [BEATS_PER_BURST_WIDTH_SRC-1:0] src_req_last_burst_length; wire [BEATS_PER_BURST_WIDTH_SRC-1:0] src_req_last_burst_length;
wire src_req_sync_transfer_start; wire src_req_sync_transfer_start;
wire src_req_xlast;
/* TODO /* TODO
wire src_response_valid; wire src_response_valid;
@ -709,6 +711,7 @@ dmac_src_axi_stream #(
.req_ready(src_req_ready), .req_ready(src_req_ready),
.req_last_burst_length(src_req_last_burst_length), .req_last_burst_length(src_req_last_burst_length),
.req_sync_transfer_start(src_req_sync_transfer_start), .req_sync_transfer_start(src_req_sync_transfer_start),
.req_xlast(src_req_xlast),
.request_id(src_request_id), .request_id(src_request_id),
.response_id(src_response_id), .response_id(src_response_id),
@ -722,6 +725,7 @@ dmac_src_axi_stream #(
.s_axis_valid(s_axis_valid), .s_axis_valid(s_axis_valid),
.s_axis_ready(s_axis_ready), .s_axis_ready(s_axis_ready),
.s_axis_data(s_axis_data), .s_axis_data(s_axis_data),
.s_axis_last(s_axis_last),
.s_axis_user(s_axis_user), .s_axis_user(s_axis_user),
.s_axis_xfer_req(s_axis_xfer_req) .s_axis_xfer_req(s_axis_xfer_req)
); );
@ -984,7 +988,7 @@ util_axis_fifo #(
); );
util_axis_fifo #( util_axis_fifo #(
.DATA_WIDTH(DMA_ADDRESS_WIDTH_SRC + BEATS_PER_BURST_WIDTH_SRC + 1), .DATA_WIDTH(DMA_ADDRESS_WIDTH_SRC + BEATS_PER_BURST_WIDTH_SRC + 2),
.ADDRESS_WIDTH(0), .ADDRESS_WIDTH(0),
.ASYNC_CLK(ASYNC_CLK_REQ_SRC) .ASYNC_CLK(ASYNC_CLK_REQ_SRC)
) i_src_req_fifo ( ) i_src_req_fifo (
@ -996,7 +1000,8 @@ util_axis_fifo #(
.s_axis_data({ .s_axis_data({
req_src_address, req_src_address,
req_length[BYTES_PER_BURST_WIDTH-1:BYTES_PER_BEAT_WIDTH_SRC], req_length[BYTES_PER_BURST_WIDTH-1:BYTES_PER_BEAT_WIDTH_SRC],
req_sync_transfer_start req_sync_transfer_start,
req_xlast
}), }),
.s_axis_room(), .s_axis_room(),
@ -1007,7 +1012,8 @@ util_axis_fifo #(
.m_axis_data({ .m_axis_data({
src_req_address, src_req_address,
src_req_last_burst_length, src_req_last_burst_length,
src_req_sync_transfer_start src_req_sync_transfer_start,
src_req_xlast
}), }),
.m_axis_level() .m_axis_level()
); );

View File

@ -56,6 +56,7 @@ module dmac_src_axi_stream #(
input s_axis_valid, input s_axis_valid,
input [S_AXIS_DATA_WIDTH-1:0] s_axis_data, input [S_AXIS_DATA_WIDTH-1:0] s_axis_data,
input [0:0] s_axis_user, input [0:0] s_axis_user,
input s_axis_last,
output s_axis_xfer_req, output s_axis_xfer_req,
input fifo_ready, input fifo_ready,
@ -65,14 +66,25 @@ module dmac_src_axi_stream #(
input req_valid, input req_valid,
output req_ready, output req_ready,
input [BEATS_PER_BURST_WIDTH-1:0] req_last_burst_length, input [BEATS_PER_BURST_WIDTH-1:0] req_last_burst_length,
input req_sync_transfer_start input req_sync_transfer_start,
input req_xlast
); );
reg needs_sync = 1'b0; reg needs_sync = 1'b0;
reg transfer_abort = 1'b0;
reg req_xlast_d = 1'b0;
wire [S_AXIS_DATA_WIDTH-1:0] data;
wire sync = s_axis_user[0]; wire sync = s_axis_user[0];
wire has_sync = ~needs_sync | sync; wire has_sync = ~needs_sync | sync;
wire sync_valid = s_axis_valid & has_sync; wire data_valid;
wire data_ready;
wire fifo_last;
assign sync_id_ret = sync_id; assign sync_id_ret = sync_id;
assign data = transfer_abort == 1'b1 ? {S_AXIS_DATA_WIDTH{1'b0}} : s_axis_data;
assign data_valid = (s_axis_valid & has_sync) | transfer_abort;
assign s_axis_ready = data_ready & ~transfer_abort;
always @(posedge s_axis_aclk) always @(posedge s_axis_aclk)
begin begin
@ -87,11 +99,36 @@ begin
end end
end end
/*
* A 'last' on the external interface indicates the end of an packet. If such a
* 'last' indicator is observed before the end of the current transfer stop
* accepting data on the external interface and complete the current transfer by
* writing zeros to the buffer.
*/
always @(posedge s_axis_aclk) begin
if (s_axis_aresetn == 1'b0) begin
transfer_abort <= 1'b0;
end else if (data_ready == 1'b1 && data_valid == 1'b1) begin
if (fifo_last == 1'b1 && req_xlast_d == 1'b1) begin
transfer_abort <= 1'b0;
end else if (s_axis_last == 1'b1) begin
transfer_abort <= 1'b1;
end
end
end
always @(posedge s_axis_aclk) begin
if(req_ready == 1'b1) begin
req_xlast_d <= req_xlast;
end
end
dmac_data_mover # ( dmac_data_mover # (
.ID_WIDTH(ID_WIDTH), .ID_WIDTH(ID_WIDTH),
.DATA_WIDTH(S_AXIS_DATA_WIDTH), .DATA_WIDTH(S_AXIS_DATA_WIDTH),
.DISABLE_WAIT_FOR_ID(0), .DISABLE_WAIT_FOR_ID(0),
.BEATS_PER_BURST_WIDTH(BEATS_PER_BURST_WIDTH) .BEATS_PER_BURST_WIDTH(BEATS_PER_BURST_WIDTH),
.LAST(1)
) i_data_mover ( ) i_data_mover (
.clk(s_axis_aclk), .clk(s_axis_aclk),
.resetn(s_axis_aresetn), .resetn(s_axis_aresetn),
@ -110,13 +147,13 @@ dmac_data_mover # (
.req_ready(req_ready), .req_ready(req_ready),
.req_last_burst_length(req_last_burst_length), .req_last_burst_length(req_last_burst_length),
.s_axi_ready(s_axis_ready), .s_axi_ready(data_ready),
.s_axi_valid(sync_valid), .s_axi_valid(data_valid),
.s_axi_data(s_axis_data), .s_axi_data(data),
.m_axi_ready(fifo_ready), .m_axi_ready(fifo_ready),
.m_axi_valid(fifo_valid), .m_axi_valid(fifo_valid),
.m_axi_data(fifo_data), .m_axi_data(fifo_data),
.m_axi_last() .m_axi_last(fifo_last)
); );
endmodule endmodule