Skip to content

Commit

Permalink
axi_dmac: Move transfer abort logic to data mover
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
larsclausen authored and Lars-Peter Clausen committed Jul 3, 2018
1 parent 92984dc commit c4cb3df
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 54 deletions.
58 changes: 47 additions & 11 deletions library/axi_dmac/data_mover.v
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ module dmac_data_mover #(

parameter ID_WIDTH = 3,
parameter DATA_WIDTH = 64,
parameter BEATS_PER_BURST_WIDTH = 4) (
parameter BEATS_PER_BURST_WIDTH = 4,
parameter ALLOW_ABORT = 0) (

input clk,
input resetn,
Expand All @@ -51,6 +52,7 @@ module dmac_data_mover #(
output s_axi_ready,
input s_axi_valid,
input [DATA_WIDTH-1:0] s_axi_data,
input s_axi_last,
input s_axi_sync,

output m_axi_valid,
Expand All @@ -60,7 +62,8 @@ module dmac_data_mover #(
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
);

localparam BEAT_COUNTER_MAX = {BEATS_PER_BURST_WIDTH{1'b1}};
Expand All @@ -81,7 +84,7 @@ reg needs_sync = 1'b0;
wire has_sync = ~needs_sync | s_axi_sync;

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;
Expand All @@ -92,18 +95,51 @@ assign response_id = id;

assign last = eot ? last_eot : last_non_eot;

assign s_axi_ready = pending_burst & active;
assign m_axi_valid = s_axi_sync_valid & pending_burst & active;
assign m_axi_data = s_axi_data;
assign s_axi_ready = (pending_burst & active) & ~transfer_abort_s;
assign m_axi_valid = (s_axi_sync_valid | transfer_abort_s) & pending_burst & active;
assign m_axi_data = transfer_abort_s == 1'b1 ? {DATA_WIDTH{1'b0}} : s_axi_data;
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
* one has s_axi_sync set. This will be the first beat that is passsed through.
*/
always @(posedge clk) begin
if (s_axi_beat == 1'b1)
if (m_axi_valid == 1'b1) begin
needs_sync <= 1'b0;
end else if (req_ready == 1'b1) begin
needs_sync <= req_sync_transfer_start;
Expand All @@ -112,15 +148,15 @@ end

// 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.
assign last_load = s_axi_beat && last_eot && eot;
assign last_load = m_axi_valid && last_eot && eot;
assign req_ready = last_load || ~active;

always @(posedge clk) begin
if (req_ready) begin
last_eot <= req_last_burst_length == 'h0;
last_non_eot <= 1'b0;
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_non_eot <= beat_counter == BEAT_COUNTER_MAX;
beat_counter <= beat_counter + 1'b1;
Expand All @@ -144,7 +180,7 @@ end

always @(*)
begin
if (s_axi_beat == 1'b1 && last == 1'b1)
if (m_axi_valid == 1'b1 && last == 1'b1)
id_next <= inc_id(id);
else
id_next <= id;
Expand Down
50 changes: 8 additions & 42 deletions library/axi_dmac/src_axi_stream.v
Original file line number Diff line number Diff line change
Expand Up @@ -68,48 +68,13 @@ module dmac_src_axi_stream #(
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 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 # (
.ID_WIDTH(ID_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 (
.clk(s_axis_aclk),
.resetn(s_axis_aresetn),
Expand All @@ -124,16 +89,17 @@ dmac_data_mover # (
.req_ready(req_ready),
.req_last_burst_length(req_last_burst_length),
.req_sync_transfer_start(req_sync_transfer_start),
.req_xlast(req_xlast),

.s_axi_ready(data_ready),
.s_axi_valid(data_valid),
.s_axi_data(data),
.s_axi_valid(s_axis_valid),
.s_axi_ready(s_axis_ready),
.s_axi_data(s_axis_data),
.s_axi_last(s_axis_last),
.s_axi_sync(s_axis_user[0]),

.m_axi_valid(fifo_valid),
.m_axi_data(fifo_data),
.m_axi_last(fifo_last),
.m_axi_eot(fifo_eot)
.m_axi_last(fifo_last)
);

endmodule
4 changes: 3 additions & 1 deletion library/axi_dmac/src_fifo_inf.v
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,14 @@ dmac_data_mover # (
.req_valid(req_valid),
.req_ready(req_ready),
.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_valid(valid),
.s_axi_data(din),
.s_axi_sync(sync),
.s_axi_last(1'b0),

.m_axi_valid(fifo_valid),
.m_axi_data(fifo_data),
Expand Down

0 comments on commit c4cb3df

Please sign in to comment.