axi_dmac: Move transfer abort logic to data mover

The transfer abort logic in the src_axi_stream module is making some
assumptions about the internal timings of the data mover module.

Move this logic inside the data mover module. This will make it easier to
update the internal logic without having to update other modules.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
main
Lars-Peter Clausen 2018-05-28 12:50:53 +02:00 committed by Lars-Peter Clausen
parent 92984dc802
commit c4cb3dfb37
3 changed files with 58 additions and 54 deletions

View File

@ -37,7 +37,8 @@ module dmac_data_mover #(
parameter ID_WIDTH = 3, parameter ID_WIDTH = 3,
parameter DATA_WIDTH = 64, parameter DATA_WIDTH = 64,
parameter BEATS_PER_BURST_WIDTH = 4) ( parameter BEATS_PER_BURST_WIDTH = 4,
parameter ALLOW_ABORT = 0) (
input clk, input clk,
input resetn, input resetn,
@ -51,6 +52,7 @@ module dmac_data_mover #(
output s_axi_ready, output s_axi_ready,
input s_axi_valid, input s_axi_valid,
input [DATA_WIDTH-1:0] s_axi_data, input [DATA_WIDTH-1:0] s_axi_data,
input s_axi_last,
input s_axi_sync, input s_axi_sync,
output m_axi_valid, output m_axi_valid,
@ -60,7 +62,8 @@ module dmac_data_mover #(
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
); );
localparam BEAT_COUNTER_MAX = {BEATS_PER_BURST_WIDTH{1'b1}}; localparam BEAT_COUNTER_MAX = {BEATS_PER_BURST_WIDTH{1'b1}};
@ -81,7 +84,7 @@ reg needs_sync = 1'b0;
wire has_sync = ~needs_sync | s_axi_sync; wire has_sync = ~needs_sync | s_axi_sync;
wire s_axi_sync_valid = has_sync & s_axi_valid; wire s_axi_sync_valid = has_sync & s_axi_valid;
wire s_axi_beat = s_axi_sync_valid & s_axi_ready; wire transfer_abort_s;
wire last_load; wire last_load;
wire last; wire last;
@ -92,18 +95,51 @@ assign response_id = id;
assign last = eot ? last_eot : last_non_eot; assign last = eot ? last_eot : last_non_eot;
assign s_axi_ready = pending_burst & active; assign s_axi_ready = (pending_burst & active) & ~transfer_abort_s;
assign m_axi_valid = s_axi_sync_valid & pending_burst & active; assign m_axi_valid = (s_axi_sync_valid | transfer_abort_s) & pending_burst & active;
assign m_axi_data = s_axi_data; assign m_axi_data = transfer_abort_s == 1'b1 ? {DATA_WIDTH{1'b0}} : s_axi_data;
assign m_axi_last = last; assign m_axi_last = last;
assign m_axi_eot = last & eot;
generate if (ALLOW_ABORT == 1) begin
reg transfer_abort = 1'b0;
reg req_xlast_d = 1'b0;
/*
* 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 clk) begin
if (resetn == 1'b0) begin
transfer_abort <= 1'b0;
end else if (m_axi_valid == 1'b1) begin
if (last == 1'b1 && eot == 1'b1 && req_xlast_d == 1'b1) begin
transfer_abort <= 1'b0;
end else if (s_axi_last == 1'b1) begin
transfer_abort <= 1'b1;
end
end
end
always @(posedge clk) begin
if (req_ready == 1'b1) begin
req_xlast_d <= req_xlast;
end
end
assign transfer_abort_s = transfer_abort;
end else begin
assign transfer_abort_s = 1'b0;
end endgenerate
/* /*
* If req_sync_transfer_start is set all incoming beats will be skipped until * If req_sync_transfer_start is set all incoming beats will be skipped until
* one has s_axi_sync set. This will be the first beat that is passsed through. * one has s_axi_sync set. This will be the first beat that is passsed through.
*/ */
always @(posedge clk) begin always @(posedge clk) begin
if (s_axi_beat == 1'b1) if (m_axi_valid == 1'b1) begin
needs_sync <= 1'b0; needs_sync <= 1'b0;
end else if (req_ready == 1'b1) begin end else if (req_ready == 1'b1) begin
needs_sync <= req_sync_transfer_start; needs_sync <= req_sync_transfer_start;
@ -112,7 +148,7 @@ end
// If we want to support zero delay between transfers we have to assert // If we want to support zero delay between transfers we have to assert
// req_ready on the same cycle on which the last load happens. // req_ready on the same cycle on which the last load happens.
assign last_load = s_axi_beat && last_eot && eot; assign last_load = m_axi_valid && last_eot && eot;
assign req_ready = last_load || ~active; assign req_ready = last_load || ~active;
always @(posedge clk) begin always @(posedge clk) begin
@ -120,7 +156,7 @@ always @(posedge clk) begin
last_eot <= req_last_burst_length == 'h0; last_eot <= req_last_burst_length == 'h0;
last_non_eot <= 1'b0; last_non_eot <= 1'b0;
beat_counter <= 'h1; beat_counter <= 'h1;
end else if (s_axi_beat == 1'b1) begin end else if (m_axi_valid == 1'b1) begin
last_eot <= beat_counter == last_burst_length; last_eot <= beat_counter == last_burst_length;
last_non_eot <= beat_counter == BEAT_COUNTER_MAX; last_non_eot <= beat_counter == BEAT_COUNTER_MAX;
beat_counter <= beat_counter + 1'b1; beat_counter <= beat_counter + 1'b1;
@ -144,7 +180,7 @@ end
always @(*) always @(*)
begin begin
if (s_axi_beat == 1'b1 && last == 1'b1) if (m_axi_valid == 1'b1 && last == 1'b1)
id_next <= inc_id(id); id_next <= inc_id(id);
else else
id_next <= id; id_next <= id;

View File

@ -68,48 +68,13 @@ module dmac_src_axi_stream #(
input req_xlast input req_xlast
); );
reg transfer_abort = 1'b0;
reg req_xlast_d = 1'b0;
wire [S_AXIS_DATA_WIDTH-1:0] data;
wire data_valid;
wire data_ready;
wire fifo_eot;
assign enabled = enable; assign enabled = enable;
assign data = transfer_abort == 1'b1 ? {S_AXIS_DATA_WIDTH{1'b0}} : s_axis_data;
assign data_valid = s_axis_valid | transfer_abort;
assign s_axis_ready = data_ready & ~transfer_abort;
/*
* 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_eot == 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),
.BEATS_PER_BURST_WIDTH(BEATS_PER_BURST_WIDTH) .BEATS_PER_BURST_WIDTH(BEATS_PER_BURST_WIDTH),
.ALLOW_ABORT(1)
) i_data_mover ( ) i_data_mover (
.clk(s_axis_aclk), .clk(s_axis_aclk),
.resetn(s_axis_aresetn), .resetn(s_axis_aresetn),
@ -124,16 +89,17 @@ 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),
.req_sync_transfer_start(req_sync_transfer_start), .req_sync_transfer_start(req_sync_transfer_start),
.req_xlast(req_xlast),
.s_axi_ready(data_ready), .s_axi_valid(s_axis_valid),
.s_axi_valid(data_valid), .s_axi_ready(s_axis_ready),
.s_axi_data(data), .s_axi_data(s_axis_data),
.s_axi_last(s_axis_last),
.s_axi_sync(s_axis_user[0]), .s_axi_sync(s_axis_user[0]),
.m_axi_valid(fifo_valid), .m_axi_valid(fifo_valid),
.m_axi_data(fifo_data), .m_axi_data(fifo_data),
.m_axi_last(fifo_last), .m_axi_last(fifo_last)
.m_axi_eot(fifo_eot)
); );
endmodule endmodule

View File

@ -98,12 +98,14 @@ dmac_data_mover # (
.req_valid(req_valid), .req_valid(req_valid),
.req_ready(req_ready), .req_ready(req_ready),
.req_last_burst_length(req_last_burst_length), .req_last_burst_length(req_last_burst_length),
.req_sync_transfer_start(req_sync_transer_start), .req_sync_transfer_start(req_sync_transfer_start),
.req_xlast(1'b0),
.s_axi_ready(ready), .s_axi_ready(ready),
.s_axi_valid(valid), .s_axi_valid(valid),
.s_axi_data(din), .s_axi_data(din),
.s_axi_sync(sync), .s_axi_sync(sync),
.s_axi_last(1'b0),
.m_axi_valid(fifo_valid), .m_axi_valid(fifo_valid),
.m_axi_data(fifo_data), .m_axi_data(fifo_data),