pluto_hdl_adi/library/axi_dmac/data_mover.v

224 lines
6.2 KiB
Coq
Raw Normal View History

// ***************************************************************************
// ***************************************************************************
// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved.
//
// In this HDL repository, there are many different and unique modules, consisting
// of various HDL (Verilog or VHDL) components. The individual modules are
// developed independently, and may be accompanied by separate and unique license
// terms.
//
// The user should read each of these license terms, and understand the
2018-03-14 14:45:47 +00:00
// freedoms and responsibilities that he or she has by using this source/core.
//
// This core is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.
//
// Redistribution and use of source or resulting binaries, with or without modification
// of this file, are permitted under one of the following two license terms:
//
// 1. The GNU General Public License version 2 as published by the
// Free Software Foundation, which can be found in the top level directory
// of this repository (LICENSE_GPL2), and also online at:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// OR
//
// 2. An ADI specific BSD license, which can be found in the top level directory
// of this repository (LICENSE_ADIBSD), and also on-line at:
// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD
// This will allow to generate bit files and not release the source code,
// as long as it attaches to an ADI device.
//
// ***************************************************************************
// ***************************************************************************
module dmac_data_mover #(
parameter ID_WIDTH = 3,
parameter DATA_WIDTH = 64,
parameter BEATS_PER_BURST_WIDTH = 4,
parameter ALLOW_ABORT = 0) (
input clk,
input resetn,
input [ID_WIDTH-1:0] request_id,
output [ID_WIDTH-1:0] response_id,
input eot,
output reg bl_valid = 'b0,
input bl_ready,
output reg [BEATS_PER_BURST_WIDTH-1:0] measured_last_burst_length,
output xfer_req,
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,
output [DATA_WIDTH-1:0] m_axi_data,
output m_axi_last,
input req_valid,
output req_ready,
input [BEATS_PER_BURST_WIDTH-1:0] req_last_burst_length,
input req_sync_transfer_start,
input req_xlast
);
localparam BEAT_COUNTER_MAX = {BEATS_PER_BURST_WIDTH{1'b1}};
`include "inc_id.vh"
hdl/library: Update the IP parameters The following IP parameters were renamed: PCORE_ID --> ID PCORE_DEVTYPE --> DEVICE_TYPE PCORE_IODELAY_GROUP --> IO_DELAY_GROUP CH_DW --> CHANNEL_DATA_WIDTH CH_CNT --> NUM_OF_CHANNELS PCORE_BUFTYPE --> DEVICE_TYPE PCORE_ADC_DP_DISABLE --> ADC_DATAPATH_DISABLE CHID --> CHANNEL_ID PCORE_DEVICE_TYPE --> DEVICE_TYPE PCORE_MMCM_BUFIO_N --> MMCM_BUFIO_N PCORE_SERDES_DDR_N --> SERDES_DDR_N PCORE_DAC_DP_DISABLE --> DAC_DATAPATH_DISABLE DP_DISABLE --> DATAPATH_DISABLE PCORE_DAC_IODELAY_ENABLE --> DAC_IODELAY_ENABLE C_BIG_ENDIAN --> BIG_ENDIAN C_M_DATA_WIDTH --> MASTER_DATA_WIDTH C_S_DATA_WIDTH --> SLAVE_DATA_WIDTH NUM_CHANNELS --> NUM_OF_CHANNELS CHANNELS --> NUM_OF_CHANNELS PCORE_4L_2L_N -->QUAD_OR_DUAL_N C_ADDRESS_WIDTH --> ADDRESS_WIDTH C_DATA_WIDTH --> DATA_WIDTH C_CLKS_ASYNC --> CLKS_ASYNC PCORE_QUAD_DUAL_N --> QUAD_DUAL_N NUM_CS --> NUM_OF_CS PCORE_DAC_CHANNEL_ID --> DAC_CHANNEL_ID PCORE_ADC_CHANNEL_ID --> ADC_CHANNEL_ID PCORE_CLK0_DIV --> CLK0_DIV PCORE_CLK1_DIV --> CLK1_DIV PCORE_CLKIN_PERIOD --> CLKIN_PERIOD PCORE_VCO_DIV --> VCO_DIV PCORE_Cr_Cb_N --> CR_CB_N PCORE_VCO_MUL --> VCO_MUL PCORE_EMBEDDED_SYNC --> EMBEDDED_SYNC PCORE_AXI_ID_WIDTH --> AXI_ID_WIDTH PCORE_ADDR_WIDTH --> ADDRESS_WIDTH DADATA_WIDTH --> DATA_WIDTH NUM_OF_NUM_OF_CHANNEL --> NUM_OF_CHANNELS DEBOUNCER_LEN --> DEBOUNCER_LENGTH ADDR_WIDTH --> ADDRESS_WIDTH C_S_AXIS_REGISTERED --> S_AXIS_REGISTERED Cr_Cb_N --> CR_CB_N ADDATA_WIDTH --> ADC_DATA_WIDTH BUFTYPE --> DEVICE_TYPE NUM_BITS --> NUM_OF_BITS WIDTH_A --> A_DATA_WIDTH WIDTH_B --> B_DATA_WIDTH CH_OCNT --> NUM_OF_CHANNELS_O M_CNT --> NUM_OF_CHANNELS_M P_CNT --> NUM_OF_CHANNELS_P CH_ICNT --> NUM_OF_CHANNELS_I CH_MCNT --> NUM_OF_CHANNELS_M 4L_2L_N --> QUAD_OR_DUAL_N SPI_CLK_ASYNC --> ASYNC_SPI_CLK MMCM_BUFIO_N --> MMCM_OR_BUFIO_N SERDES_DDR_N --> SERDES_OR_DDR_N CLK_ASYNC --> ASYNC_CLK CLKS_ASYNC --> ASYNC_CLK SERDES --> SERDES_OR_DDR_N GTH_GTX_N --> GTH_OR_GTX_N IF_TYPE --> DDR_OR_SDR_N PARALLEL_WIDTH --> DATA_WIDTH ADD_SUB --> ADD_OR_SUB_N A_WIDTH --> A_DATA_WIDTH CONST_VALUE --> B_DATA_VALUE IO_BASEADDR --> BASE_ADDRESS IO_WIDTH --> DATA_WIDTH QUAD_DUAL_N --> QUAD_OR_DUAL_N AXI_ADDRLIMIT --> AXI_ADDRESS_LIMIT ADDRESS_A_DATA_WIDTH --> A_ADDRESS_WIDTH ADDRESS_B_DATA_WIDTH --> B_ADDRESS_WIDTH MODE_OF_ENABLE --> CONTROL_TYPE CONTROL_TYPE --> LEVEL_OR_PULSE_N IQSEL --> Q_OR_I_N MMCM --> MMCM_OR_BUFR_N
2015-08-19 11:11:47 +00:00
reg [BEATS_PER_BURST_WIDTH-1:0] last_burst_length = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] beat_counter = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] beat_counter_minus_one = 'h0;
hdl/library: Update the IP parameters The following IP parameters were renamed: PCORE_ID --> ID PCORE_DEVTYPE --> DEVICE_TYPE PCORE_IODELAY_GROUP --> IO_DELAY_GROUP CH_DW --> CHANNEL_DATA_WIDTH CH_CNT --> NUM_OF_CHANNELS PCORE_BUFTYPE --> DEVICE_TYPE PCORE_ADC_DP_DISABLE --> ADC_DATAPATH_DISABLE CHID --> CHANNEL_ID PCORE_DEVICE_TYPE --> DEVICE_TYPE PCORE_MMCM_BUFIO_N --> MMCM_BUFIO_N PCORE_SERDES_DDR_N --> SERDES_DDR_N PCORE_DAC_DP_DISABLE --> DAC_DATAPATH_DISABLE DP_DISABLE --> DATAPATH_DISABLE PCORE_DAC_IODELAY_ENABLE --> DAC_IODELAY_ENABLE C_BIG_ENDIAN --> BIG_ENDIAN C_M_DATA_WIDTH --> MASTER_DATA_WIDTH C_S_DATA_WIDTH --> SLAVE_DATA_WIDTH NUM_CHANNELS --> NUM_OF_CHANNELS CHANNELS --> NUM_OF_CHANNELS PCORE_4L_2L_N -->QUAD_OR_DUAL_N C_ADDRESS_WIDTH --> ADDRESS_WIDTH C_DATA_WIDTH --> DATA_WIDTH C_CLKS_ASYNC --> CLKS_ASYNC PCORE_QUAD_DUAL_N --> QUAD_DUAL_N NUM_CS --> NUM_OF_CS PCORE_DAC_CHANNEL_ID --> DAC_CHANNEL_ID PCORE_ADC_CHANNEL_ID --> ADC_CHANNEL_ID PCORE_CLK0_DIV --> CLK0_DIV PCORE_CLK1_DIV --> CLK1_DIV PCORE_CLKIN_PERIOD --> CLKIN_PERIOD PCORE_VCO_DIV --> VCO_DIV PCORE_Cr_Cb_N --> CR_CB_N PCORE_VCO_MUL --> VCO_MUL PCORE_EMBEDDED_SYNC --> EMBEDDED_SYNC PCORE_AXI_ID_WIDTH --> AXI_ID_WIDTH PCORE_ADDR_WIDTH --> ADDRESS_WIDTH DADATA_WIDTH --> DATA_WIDTH NUM_OF_NUM_OF_CHANNEL --> NUM_OF_CHANNELS DEBOUNCER_LEN --> DEBOUNCER_LENGTH ADDR_WIDTH --> ADDRESS_WIDTH C_S_AXIS_REGISTERED --> S_AXIS_REGISTERED Cr_Cb_N --> CR_CB_N ADDATA_WIDTH --> ADC_DATA_WIDTH BUFTYPE --> DEVICE_TYPE NUM_BITS --> NUM_OF_BITS WIDTH_A --> A_DATA_WIDTH WIDTH_B --> B_DATA_WIDTH CH_OCNT --> NUM_OF_CHANNELS_O M_CNT --> NUM_OF_CHANNELS_M P_CNT --> NUM_OF_CHANNELS_P CH_ICNT --> NUM_OF_CHANNELS_I CH_MCNT --> NUM_OF_CHANNELS_M 4L_2L_N --> QUAD_OR_DUAL_N SPI_CLK_ASYNC --> ASYNC_SPI_CLK MMCM_BUFIO_N --> MMCM_OR_BUFIO_N SERDES_DDR_N --> SERDES_OR_DDR_N CLK_ASYNC --> ASYNC_CLK CLKS_ASYNC --> ASYNC_CLK SERDES --> SERDES_OR_DDR_N GTH_GTX_N --> GTH_OR_GTX_N IF_TYPE --> DDR_OR_SDR_N PARALLEL_WIDTH --> DATA_WIDTH ADD_SUB --> ADD_OR_SUB_N A_WIDTH --> A_DATA_WIDTH CONST_VALUE --> B_DATA_VALUE IO_BASEADDR --> BASE_ADDRESS IO_WIDTH --> DATA_WIDTH QUAD_DUAL_N --> QUAD_OR_DUAL_N AXI_ADDRLIMIT --> AXI_ADDRESS_LIMIT ADDRESS_A_DATA_WIDTH --> A_ADDRESS_WIDTH ADDRESS_B_DATA_WIDTH --> B_ADDRESS_WIDTH MODE_OF_ENABLE --> CONTROL_TYPE CONTROL_TYPE --> LEVEL_OR_PULSE_N IQSEL --> Q_OR_I_N MMCM --> MMCM_OR_BUFR_N
2015-08-19 11:11:47 +00:00
reg [ID_WIDTH-1:0] id = 'h00;
reg [ID_WIDTH-1:0] id_next = 'h00;
reg pending_burst = 1'b0;
reg active = 1'b0;
reg last_eot = 1'b0;
reg last_non_eot = 1'b0;
reg needs_sync = 1'b0;
wire has_sync = ~needs_sync | s_axi_sync;
wire s_axi_sync_valid = has_sync & s_axi_valid;
wire transfer_abort_s;
wire last_load;
wire last;
assign xfer_req = active;
assign response_id = id;
assign last = eot ? last_eot : last_non_eot;
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;
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 (m_axi_valid == 1'b1) begin
needs_sync <= 1'b0;
end else if (req_ready == 1'b1) begin
needs_sync <= req_sync_transfer_start;
end
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 = m_axi_valid && last_eot && eot;
assign req_ready = last_load || ~active;
2014-03-20 16:22:18 +00:00
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 (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;
end
end
always @(posedge clk) begin
if (req_ready)
last_burst_length <= req_last_burst_length;
end
always @(posedge clk) begin
if (req_ready) begin
beat_counter_minus_one <= 'h0;
end else if (m_axi_valid == 1'b1) begin
beat_counter_minus_one <= beat_counter;
end
end
always @(posedge clk) begin
if (last_load) begin
bl_valid <= 1'b1;
measured_last_burst_length <= beat_counter_minus_one;
end else if (bl_ready) begin
bl_valid <= 1'b0;
end
end
always @(posedge clk) begin
axi_dmac: Rework transfer shutdown 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 <lars@metafoo.de>
2017-09-21 14:02:44 +00:00
if (resetn == 1'b0) begin
active <= 1'b0;
axi_dmac: Rework transfer shutdown 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 <lars@metafoo.de>
2017-09-21 14:02:44 +00:00
end else if (req_valid == 1'b1) begin
active <= 1'b1;
axi_dmac: Rework transfer shutdown 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 <lars@metafoo.de>
2017-09-21 14:02:44 +00:00
end else if (last_load == 1'b1) begin
active <= 1'b0;
end
end
always @(*)
begin
if (m_axi_valid == 1'b1 && last == 1'b1)
id_next <= inc_id(id);
else
id_next <= id;
end
always @(posedge clk) begin
if (resetn == 1'b0) begin
id <= 'h0;
end else begin
id <= id_next;
end
end
always @(posedge clk) begin
pending_burst <= id_next != request_id;
end
endmodule