Skip to content

Commit

Permalink
axi_dmac: Rework transfer shutdown
Browse files Browse the repository at this point in the history
The DMAC allows a transfer to be aborted. When a transfer is aborted the
DMAC shuts down as fast as possible while still completing any pending
transactions as required by the protocol specifications of the port. E.g.
for AXI-MM this means to complete all outstanding bursts.

Once the DMAC has entered an idle state a special synchronization signal is
send to all modules. This synchronization signal instructs them to flush
the pipeline and remove any stale data and metadata associated with the
aborted transfer. Once all data has been flushed the DMAC enters the
shutdown state and is ready for the next transfer.

In addition each module has a reset that resets the modules state and is
used at system startup to bring them into a consistent state.

Re-work the shutdown process to instead of flushing the pipeline re-use the
startup reset signal also for shutdown.

To manage the reset signal generation introduce the reset manager module.
It contains a state machine that will assert the reset signals in the
correct order and for the appropriate duration in case of a transfer
shutdown.

The reset signal is asserted in all domains until it has been asserted for
at least 4 clock cycles in the slowest domain. This ensures that the reset
signal is not de-asserted in the faster domains before the slower domains
have had a chance to process the reset signal.

In addition the reset signal is de-asserted in the opposite direction of
the data flow. This ensures that the data sink is ready to receive data
before the data source can start sending data. This simplifies the internal
handshaking.

This approach has multiple advantages.
 * Issuing a reset and removing all state takes less time than
   explicitly flushing one sample per clock cycle at a time.
 * It simplifies the logic in the faster clock domains at the expense of
   more complicated logic in the slower control clock domain. This allows
   for higher fMax on the data paths.
 * Less signals to synchronize from the control domain to the data domains

The implementation of the pause mode has also slightly changed. Pause is
now a simple disable of the data domains. When the transfer is resumed
after a pause the data domains are re-enabled and continue at their
previous state.

Signed-off-by: Lars-Peter Clausen <[email protected]>
  • Loading branch information
larsclausen authored and Lars-Peter Clausen committed Jul 3, 2018
1 parent 95c98c6 commit 02bc91a
Show file tree
Hide file tree
Showing 27 changed files with 710 additions and 395 deletions.
1 change: 1 addition & 0 deletions library/axi_dmac/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ GENERIC_DEPS += address_generator.v
GENERIC_DEPS += axi_dmac.v
GENERIC_DEPS += axi_dmac_regmap.v
GENERIC_DEPS += axi_dmac_regmap_request.v
GENERIC_DEPS += axi_dmac_reset_manager.v
GENERIC_DEPS += axi_dmac_transfer.v
GENERIC_DEPS += axi_register_slice.v
GENERIC_DEPS += data_mover.v
Expand Down
51 changes: 21 additions & 30 deletions library/axi_dmac/address_generator.v
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ module dmac_address_generator #(

output reg [ID_WIDTH-1:0] id,
input [ID_WIDTH-1:0] request_id,
input sync_id,

input eot,

Expand Down Expand Up @@ -99,21 +98,21 @@ reg last = 1'b0;
always @(posedge clk) begin
if (resetn == 1'b0) begin
enabled <= 1'b0;
end else begin
if (enable)
enabled <= 1'b1;
else if (~addr_valid)
enabled <= 1'b0;
end else if (enable == 1'b1) begin
enabled <= 1'b1;
end else if (addr_valid == 1'b0) begin
enabled <= 1'b0;
end
end

always @(posedge clk) begin
if (addr_valid == 1'b0) begin
last <= eot;
if (eot == 1'b1)
if (eot == 1'b1) begin
length <= last_burst_len;
else
end else begin
length <= MAX_LENGTH;
end
end
end

Expand All @@ -131,34 +130,26 @@ always @(posedge clk) begin
req_ready <= 1'b1;
addr_valid <= 1'b0;
end else begin
if (~enabled) begin
req_ready <= 1'b1;
end else if (req_ready) begin
if (req_valid && enable) begin
req_ready <= 1'b0;
end
end else begin
if (addr_valid && addr_ready) begin
addr_valid <= 1'b0;
if (last)
req_ready <= 1'b1;
end else if (id != request_id && enable) begin
addr_valid <= 1'b1;
end
if (req_ready == 1'b1) begin
req_ready <= ~req_valid;
end else if (addr_valid == 1'b1 && addr_ready == 1'b1) begin
addr_valid <= 1'b0;
req_ready <= last;
end else if (id != request_id && enable == 1'b1) begin
addr_valid <= 1'b1;
end
end
end

always @(posedge clk) begin
if (resetn == 1'b0) begin
id <='h0;
addr_valid_d1 <= 1'b0;
end else begin
addr_valid_d1 <= addr_valid;
if ((addr_valid && ~addr_valid_d1) ||
(sync_id && id != request_id))
id <= inc_id(id);
addr_valid_d1 <= addr_valid;
end

always @(posedge clk) begin
if (resetn == 1'b0) begin
id <= 'h0;
end else if (addr_valid == 1'b1 && addr_valid_d1 == 1'b0) begin
id <= inc_id(id);
end
end

Expand Down
10 changes: 5 additions & 5 deletions library/axi_dmac/axi_dmac.v
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ wire [ID_WIDTH-1:0] src_request_id;
wire [ID_WIDTH-1:0] src_data_id;
wire [ID_WIDTH-1:0] src_address_id;
wire [ID_WIDTH-1:0] src_response_id;
wire [7:0] dbg_status;
wire [11:0] dbg_status;
wire [31:0] dbg_ids0;
wire [31:0] dbg_ids1;

Expand Down Expand Up @@ -430,11 +430,11 @@ axi_dmac_transfer #(
.AXI_LENGTH_WIDTH_SRC(8-(4*DMA_AXI_PROTOCOL_SRC)),
.AXI_LENGTH_WIDTH_DEST(8-(4*DMA_AXI_PROTOCOL_DEST))
) i_transfer (
.req_clk(s_axi_aclk),
.req_resetn(s_axi_aresetn),
.ctrl_clk(s_axi_aclk),
.ctrl_resetn(s_axi_aresetn),

.enable(ctrl_enable),
.pause(ctrl_pause),
.ctrl_enable(ctrl_enable),
.ctrl_pause(ctrl_pause),

.req_valid(up_dma_req_valid),
.req_ready(up_dma_req_ready),
Expand Down
22 changes: 20 additions & 2 deletions library/axi_dmac/axi_dmac_constr.sdc
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,28 @@
set_false_path -to [get_registers *axi_dmac*cdc_sync_stage1*]
set_false_path -from [get_registers *axi_dmac*cdc_sync_fifo_ram*]
set_false_path -from [get_registers *axi_dmac*eot_mem*]
set_false_path -to [get_registers *axi_dmac*reset_shift*]

# Reset manager
set_false_path \
-from [get_registers {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|do_reset}] \
-to [get_pins -compatibility_mode {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_async[*]|clrn}]

set_false_path \
-from [get_registers {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_async[0]}] \
-to [get_registers {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_async[3]}]

set_false_path \
-from [get_registers {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_async[0]}] \
-to [get_pins -compatibility_mode {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_sync_in|clrn}]

set_false_path \
-from [get_registers {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_sync[0]}] \
-to [get_pins -compatibility_mode {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_sync_in|clrn}]

# Debug signals
set_false_path -from [get_registers *axi_dmac*|*i_request_arb*|cdc_sync_stage2*] -to [get_registers *axi_dmac*up_rdata*]
set_false_path -from [get_registers *axi_dmac*|*i_request_arb*|*id*] -to [get_registers *axi_dmac*up_rdata*]
set_false_path -from [get_registers *axi_dmac*|*i_request_arb*|address*] -to [get_registers *axi_dmac*up_rdata*]

set_false_path \
-from [get_registers {*|axi_dmac_transfer:i_transfer|axi_dmac_reset_manager:i_reset_manager|reset_gen[*].reset_sync[0]}] \
-to [get_registers {*|axi_dmac_regmap:i_regmap|up_rdata[*]}]
36 changes: 34 additions & 2 deletions library/axi_dmac/axi_dmac_constr.ttcl
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,37 @@ set_max_delay -quiet -datapath_only \
<: } :>
# Reset signals
set_false_path -quiet \
-from $req_clk \
-to [get_pins -quiet -hier *reset_shift_reg*/PRE]
-from [get_cells -quiet -hier *do_reset_reg* \
-filter {NAME =~ *i_reset_manager* && IS_SEQUENTIAL}] \
-to [get_pins -quiet -hier *reset_async_reg*/PRE]

set_false_path -quiet \
-from [get_cells -quiet -hier *reset_async_reg[0] \
-filter {NAME =~ *i_reset_manager* && IS_SEQUENTIAL}] \
-to [get_cells -quiet -hier *reset_async_reg[3]* \
-filter {NAME =~ *i_reset_manager* && IS_SEQUENTIAL}]

set_false_path -quiet \
-from [get_cells -quiet -hier *reset_async_reg[0] \
-filter {NAME =~ *i_reset_manager* && IS_SEQUENTIAL}] \
-to [get_pins -quiet -hier *reset_sync_in_reg*/PRE \
-filter {NAME =~ *i_reset_manager*}]

set_false_path -quiet \
-from [get_cells -quiet -hier *reset_sync_reg[0] \
-filter {NAME =~ *i_reset_manager* && IS_SEQUENTIAL}] \
-to [get_pins -quiet -hier *reset_sync_in_reg*/PRE \
-filter {NAME =~ *i_reset_manager*}]

set_property -dict { \
SHREG_EXTRACT NO \
ASYNC_REG TRUE \
} [get_cells -quiet -hier *reset_shift_reg*]

set_property -dict { \
SHREG_EXTRACT NO \
ASYNC_REG TRUE \
} [get_cells -quiet -hier *reset_sync_reg*]

# Ignore timing for debug signals to register map
<: if {!$disable_debug_registers} { :>
Expand All @@ -162,4 +191,7 @@ set_false_path -quiet \
set_false_path -quiet \
-from [get_cells -quiet -hier *address_reg* -filter {name =~ *i_addr_gen* && IS_SEQUENTIAL}] \
-to [get_cells -quiet -hier *up_rdata_reg* -filter {IS_SEQUENTIAL}]
set_false_path -quiet \
-from [get_cells -quiet -hier *reset_sync_reg* -filter {name =~ *i_reset_manager* && IS_SEQUENTIAL}] \
-to [get_cells -quiet -hier *up_rdata_reg* -filter {IS_SEQUENTIAL}]
<: } :>
1 change: 1 addition & 0 deletions library/axi_dmac/axi_dmac_hw.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ad_ip_files axi_dmac [list \
resp.h \
axi_dmac_regmap.v \
axi_dmac_regmap_request.v \
axi_dmac_reset_manager.v \
axi_dmac_transfer.v \
address_generator.v \
data_mover.v \
Expand Down
1 change: 1 addition & 0 deletions library/axi_dmac/axi_dmac_ip.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ adi_ip_files axi_dmac [list \
"resp.h" \
"axi_dmac_regmap.v" \
"axi_dmac_regmap_request.v" \
"axi_dmac_reset_manager.v" \
"axi_dmac_transfer.v" \
"address_generator.v" \
"data_mover.v" \
Expand Down
2 changes: 1 addition & 1 deletion library/axi_dmac/axi_dmac_regmap.v
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ module axi_dmac_regmap #(
// Debug interface
input [DMA_AXI_ADDR_WIDTH-1:0] dbg_src_addr,
input [DMA_AXI_ADDR_WIDTH-1:0] dbg_dest_addr,
input [7:0] dbg_status,
input [11:0] dbg_status,
input [31:0] dbg_ids0,
input [31:0] dbg_ids1
);
Expand Down
Loading

0 comments on commit 02bc91a

Please sign in to comment.