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
parent
da28ee3cce
commit
c6073954d9
|
@ -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),
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
);
|
);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue