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 [DMA_DATA_WIDTH_SRC-1:0] s_axis_data,
input [0:0] s_axis_user,
input s_axis_last,
output s_axis_xfer_req,
// Master streaming AXI interface
@ -377,7 +378,7 @@ begin
up_dma_req_valid <= 1'b0;
up_scratch <= 'h00;
up_dma_cyclic <= 1'b0;
up_axis_xlast <= 1'b0;
up_axis_xlast <= 1'b1;
up_wack <= 1'b0;
end else begin
up_wack <= up_wreq;
@ -628,6 +629,7 @@ dmac_request_arb #(
.s_axis_valid(s_axis_valid),
.s_axis_data(s_axis_data),
.s_axis_user(s_axis_user),
.s_axis_last(s_axis_last),
.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"} \
{"s_axis_valid" "TVALID"} \
{"s_axis_data" "TDATA"} \
{"s_axis_last" "TLAST"} \
{"s_axis_user" "TUSER"} ]
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" \
"(spirit:decode(id('MODELPARAM_VALUE.DMA_TYPE_DEST')) = 2)"
foreach port {"m_dest_axi_aresetn" "m_src_axi_aresetn" "s_axis_valid" \
"s_axis_data" "m_axis_ready" "fifo_wr_en" "fifo_wr_din" "fifo_rd_en"} {
foreach port {"m_dest_axi_aresetn" "m_src_axi_aresetn" \
"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]
}

View File

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

View File

@ -56,6 +56,7 @@ module dmac_src_axi_stream #(
input s_axis_valid,
input [S_AXIS_DATA_WIDTH-1:0] s_axis_data,
input [0:0] s_axis_user,
input s_axis_last,
output s_axis_xfer_req,
input fifo_ready,
@ -65,14 +66,25 @@ module dmac_src_axi_stream #(
input req_valid,
output req_ready,
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 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 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 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)
begin
@ -87,11 +99,36 @@ begin
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 # (
.ID_WIDTH(ID_WIDTH),
.DATA_WIDTH(S_AXIS_DATA_WIDTH),
.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 (
.clk(s_axis_aclk),
.resetn(s_axis_aresetn),
@ -110,13 +147,13 @@ dmac_data_mover # (
.req_ready(req_ready),
.req_last_burst_length(req_last_burst_length),
.s_axi_ready(s_axis_ready),
.s_axi_valid(sync_valid),
.s_axi_data(s_axis_data),
.s_axi_ready(data_ready),
.s_axi_valid(data_valid),
.s_axi_data(data),
.m_axi_ready(fifo_ready),
.m_axi_valid(fifo_valid),
.m_axi_data(fifo_data),
.m_axi_last()
.m_axi_last(fifo_last)
);
endmodule